Как добавить поток данных в файл MXF (используя mpeg2video) с помощью FFmpeg и C / C ++ - PullRequest
1 голос
/ 25 марта 2019

Я немного застрял здесь, пытаясь создать файл MXF с потоком данных на нем. У меня есть несколько видео файлов MXF, которые содержат этот стандарт

**1 Video Stream:
     Stream #0:0: Video: mpeg2video (4:2:2), yuv422p(tv, bt709, top first), 1920x1080 [SAR 1:1 DAR 16:9], 50000 kb/s, 29.9
16 audio streams
     Audio: pcm_s24le, 48000 Hz, 1 channels, s32 (24 bit), 1152 kb/s
1 Data Stream:
     Data: none**

Этот поток данных содержит личные данные внутри видеофайла. Я могу откройте этот поток и данные действительно есть. Все в порядке. Но когда я пытаюсь чтобы создать файл точно так же, каждый раз, когда я вызываю "avformat_write_header" возвращает ошибку.

Если я прокомментирую создание этих потоков данных, видеофайл будет успешно создано.

Если я изменяю на «mpegts» с этим потоком данных, видеофайл также успешно создано.

Но я не могу использовать mpets, и мне нужен этот поток данных.

Я знаю, что возможно MXF с потоком данных, потому что у меня есть файлы оригиналов которые имеют эту комбинацию.

Итак, я знаю, что чего-то не хватает в моем коде.

Это способ создания потока данных:

 void CFFmpegVideoWriter::addDataStream(EOutputStream *ost, AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
    {
        AVCodecParameters *par;

        ost->stream = avformat_new_stream(oc, NULL);
        if (ost->stream == NULL)
        {
            fprintf(stderr, "OOooohhh man: avformat_new_stream() failed.\n");
            return;
        }

        par = ost->stream->codecpar;
        ost->stream->index = 17;
        par->codec_id = AV_CODEC_ID_NONE;
        par->codec_type = AVMEDIA_TYPE_DATA;

        ost->stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    }

файл открывается так:

CFFMpegVideoWriter::CFFMpegVideoWriter(QString outputfilename) : QThread()
{
    av_register_all();
    avcodec_register_all();

    isOpen = false;
    shouldClose = false;

    frameIndex = 0;

#ifdef __linux__
    QByteArray bFilename = outputfilename.toUtf8();
#else
    QByteArray bFilename = outputfilename.toLatin1();
#endif

    const char* filename = bFilename.data();

    codecContext = NULL;

    //encontra o formato desejado...
    outputFormat = av_guess_format("mp2v", filename, nullptr);
    if (!outputFormat)
    {
        qDebug("Could not find suitable output format\n");
        return;
    }

    //encontra o codec...
    codec = avcodec_find_encoder(outputFormat->video_codec);
    if (!codec)
    {
        qDebug( "Codec not found\n");
        return;
    }

    //aloca o contexto do codec...
    codecContext = avcodec_alloc_context3(codec);
    codecContext->field_order = AV_FIELD_TT;
    codecContext->profile = FF_PROFILE_MPEG2_422;

    //aloca o contexto do formato...
    formatContext = avformat_alloc_context();
    formatContext->oformat = outputFormat;

    //aloca o contexto da midia de saida...
    avformat_alloc_output_context2(&formatContext, NULL, NULL, filename);
    if (!formatContext)
    {
        qDebug("Erro");
        return;
    }

    videoStream.tmp_frame = NULL;
    videoStream.swr_ctx = NULL;

    //adiciona a stream de video...
    if (outputFormat->video_codec != AV_CODEC_ID_NONE)
    {
        addVideoStream(&videoStream, formatContext, &video_codec, outputFormat->video_codec);       
    }

    //adiciona as 16 streams de audio...
    if (outputFormat->audio_codec != AV_CODEC_ID_NONE)
    {
        for (int i = 0; i < 16; i++)
        {
            addAudioStream(&audioStream[i], formatContext, &audio_codec, outputFormat->audio_codec);
        }       
    }

    addDataStream(&datastream, formatContext, &video_codec, outputFormat->video_codec);     

    videoStream.sws_ctx = NULL;
    for (int i = 0; i < 16; i++)
    {
        audioStream[i].sws_ctx = NULL;
    }   
    opt = NULL;


    //carreca o codec de video para stream de video...      
    initVideoCodec(formatContext, video_codec, &videoStream, opt);


    //carrega o codec de audio para stream de audio...s
    for (int i = 0; i < 16; i++)
    {
        initAudioCodec(formatContext, audio_codec, &audioStream[i], opt);
    }


    av_dump_format(formatContext, 0, filename, 1);

    //abrea o arquivo de saida..
    if (!(outputFormat->flags & AVFMT_NOFILE))
    {
        ret = avio_open(&formatContext->pb, filename, AVIO_FLAG_WRITE);
        if (ret < 0)
        {
            qDebug("Could not open'%s", filename);
            return;
        }
    }

    //escreve o cabecalho do arquivo...
    ret = avformat_write_header(formatContext, &opt);
    if (ret < 0)
    {
        qDebug("Error occurred when opening output file");
        return;
    }

    isOpen = true;

    QThread::start();
}

Код всегда терпит неудачу при вызове «avformat_write_header».

Но если я удаляю "поток данных" или меняю его на mpegts, все работает нормально.

Есть идеи, что я здесь делаю не так?

Спасибо, что прочитали это.

Хельмут

1 Ответ

1 голос
/ 26 марта 2019

После нескольких долгих часов, пытаясь найти много решений, я нашел, что было не так. Мне пришлось добавить элемент метаданных, указывающий тип данных.

В моем случае тип данных был "vbi_vanc_smpte_436M", который поддерживается MXF.

Итак, я делаю с:

av_dict_set(&out_stream->metadata, "data_type", "vbi_vanc_smpte_436M",  AV_DICT_IGNORE_SUFFIX);  

Тогда все отлично работает.

Я надеюсь, что это может помочь кому-то еще с той же проблемой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...