Пропускная способность FFMPEG для записи некорректного кодирования контейнера RTSP / H264 в MP4 - PullRequest
0 голосов
/ 14 января 2019

Здравствуйте! Я использую ffmpeg 3.4.2 для записи пара RTSP h264 с IP-камеры. У меня есть рабочий пример, однако в начале я вижу несколько поврежденных изображений, через пару секунд видео отображается правильно. Мне было интересно, если это проблема времени.

enter image description here

Исходный код, который иллюстрирует открытие и чтение потока RTSP и запись его в контейнер MP4.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/time.h>

extern "C" {
  #include <libavcodec/avcodec.h>
  #include <libavutil/opt.h>
  #include <libavutil/imgutils.h>
  #include <libavformat/avformat.h>
  #include <libavformat/avio.h>
  #include <libswscale/swscale.h>
}

time_t get_time()
{
  struct timeval tv;

  gettimeofday( &tv, NULL );

  return tv.tv_sec;
}

int main(int argc, char **argv)
{
    const char *filename, *codec_name;
    const AVCodec *codec;
    AVCodecContext *c= NULL;
    int i, ret, x, y;


    // Open the initial context variables that are needed
    AVFormatContext* format_ctx = avformat_alloc_context();
    int video_stream_index;

    // Register everything
    av_register_all();
    avformat_network_init();

    //open RTSP

    AVDictionary *ifmtdict;
    av_dict_set(&ifmtdict, "rtsp_transport", "tcp", 0);

    if (avformat_open_input(&format_ctx, "rtsp://192.168.0.84/user=admin_password=_channel=1_stream=0.sdp",
            NULL, &ifmtdict) != 0) {
        return EXIT_FAILURE;
    }

    if (avformat_find_stream_info(format_ctx, NULL) < 0) {
        return EXIT_FAILURE;
    }

    //search video stream
    for (int i = 0; i < format_ctx->nb_streams; i++) {
        if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
            video_stream_index = i;
    }

    AVPacket packet;
    av_init_packet(&packet);

    AVStream* stream = NULL;
    int cnt = 0;

    //start reading packets from stream and write them to file
    av_read_play(format_ctx);    //play RTSP

    // Get the codec
    codec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!codec) {
        exit(1);
    }

    // Prepare the output
    AVFormatContext* oc = avformat_alloc_context();
    oc->oformat = av_guess_format(NULL, "video.mp4", NULL);
    avio_open2(&oc->pb, "video.mp4", AVIO_FLAG_WRITE, NULL, NULL);

    // Write header
    stream = avformat_new_stream(oc, (AVCodec*) format_ctx->streams[video_stream_index]->codec->codec);
    avcodec_parameters_copy(stream->codecpar, format_ctx->streams[video_stream_index]->codecpar);
    stream->sample_aspect_ratio = format_ctx->streams[video_stream_index]->codec->sample_aspect_ratio;
    stream->codecpar->codec_tag  = 0;
    stream->time_base = format_ctx->streams[video_stream_index]->time_base;
    avformat_write_header(oc, NULL);

    time_t timenow, timestart;
    timestart = timenow = get_time();
    bool got_key_frame = 0;

    while (av_read_frame(format_ctx, &packet) >= 0 && cnt < 200000) { //read ~ 200000 frames
        if (packet.stream_index == video_stream_index) {    //packet is video
            // Make sure we start on a key frame
            if ( !got_key_frame && timestart == timenow && ! ( packet.flags & AV_PKT_FLAG_KEY ) ) {
              timestart = timenow = get_time();
              continue;
            }
            got_key_frame = 1;
            std::cout << cnt << std::endl;
            av_interleaved_write_frame( oc, &packet );
            cnt++;
        }
      av_free_packet(&packet);
      av_init_packet(&packet);
      timenow = get_time();
    }

    av_write_trailer(oc);
    avcodec_close(stream->codec);
    avio_close(oc->pb);
    avformat_free_context(oc);

    av_read_pause(format_ctx);

    avcodec_free_context(&c);
    avformat_network_deinit();

    return 0;
}

1 Ответ

0 голосов
/ 16 января 2019

Поток H.264 состоит из группы кадров (GOP). Обычно вы можете начать декодирование только на границах GOP. Возможно, вам придется подождать кадр IDR, прежде чем передавать видео пакеты на устройство записи MP4.

...