как изменить индекс потока в libavformat - PullRequest
3 голосов
/ 03 января 2012

Я новичок в ffmpeg. У меня проблема, когда на некоторых носителях есть несколько аудиопотоков. Предположим, в файле MKV имеется три аудиопотока (MP3, WMA и WMAPro)

Как изменить индекс потока при демультиплексировании с помощью:

AVPacket inputPacket;
ret = av_read_frame(avInputFmtCtx, &inputPacket)

Так что я ищу что-то вроде change_stream_index (int streamindex), и когда я вызываю эту функцию (предположим, change_stream_index (2)), следующий вызов av_read_frame будет демультиплексировать кадр WMAPro вместо MP3.

Спасибо, ребята!

Ответы [ 2 ]

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

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

Решением для меня было установить атрибут discard всех потоков, которые меня не интересуют, на AVDISCARD_ALL. Например, чтобы выбрать только один поток с индексом 71, вы можете сделать это:

int32_t stream_index = 71;
for(int32_t i = 0; i<pFormatContext->nb_streams; i++)
{
  if(stream_index != i) pFormatContext->streams[i]->discard = AVDISCARD_ALL;
}

после этого вы можете позвонить av_seek_frame или av_read_frame, и обрабатывается только трек 71.

Только для справки, вот список всех доступных типов сброса:

AVDISCARD_NONE    =-16, ///< discard nothing
AVDISCARD_DEFAULT =  0, ///< discard useless packets like 0 size packets in avi
AVDISCARD_NONREF  =  8, ///< discard all non reference
AVDISCARD_BIDIR   = 16, ///< discard all bidirectional frames
AVDISCARD_NONINTRA= 24, ///< discard all non intra frames
AVDISCARD_NONKEY  = 32, ///< discard all frames except keyframes
AVDISCARD_ALL     = 48, ///< discard all
0 голосов
/ 21 января 2012

Ну, сначала вы проверяете количество потоков на входе. Затем вы записываете их в некоторый буфер (в моем случае у меня есть только 2 потока, но вы можете легко это расширить)

ptrFormatContext = avformat_alloc_context();

    if(avformat_open_input(&ptrFormatContext, filename, NULL, NULL) != 0 )
    {
        qDebug("Error opening the input");
        exit(-1);
    }
    if(av_find_stream_info( ptrFormatContext) < 0)
    {
        qDebug("Could not find any stream info");
        exit(-2);
    }
    dump_format(ptrFormatContext, 0, filename, (int) NULL);

    for(i=0; i<ptrFormatContext->nb_streams; i++)
    {
        switch(ptrFormatContext->streams[i]->codec->codec_type)
        {
        case AVMEDIA_TYPE_VIDEO:
        {
            if(videoStream < 0) videoStream = i;
            break;
        }
        case AVMEDIA_TYPE_AUDIO:
        {
            if(audioStream < 0) audioStream = i;
        }
        }
    }
    if(audioStream == -1)
    {
        qDebug("Could not find any audio stream");
        exit(-3);
    }
    if(videoStream == -1)
    {
        qDebug("Could not find any video stream");
        exit(-4);
    }

Поскольку вы не знаете, в каком порядке поступают потоки, вам также нужно проверить имя кодека: ptrFormatContext->streams[i]->codec->codec_name и затем сохранить индекс для соответствующего target_format. Тогда вы можете просто получить доступ к потоку через данный индекс:

while(av_read_frame(ptrFormatContext,&ptrPacket) >= 0)
    {
        if(ptrPacket.stream_index == videoStream)
        {
            //decode the video stream to raw format
            if(avcodec_decode_video2(ptrCodecCtxt, ptrFrame, &frameFinished, &ptrPacket) < 0)
            {
                qDebug("Error decoding the Videostream");
                exit(-13);
            }
            if(frameFinished)
            {
                printf("%s\n", (char*) ptrPacket.data);
//encode the video stream to target format
//                av_free_packet(&ptrPacket);
            }
        }
        else if (ptrPacket.stream_index == audioStream)
        {
            //decode the audio stream to raw format
//            if(avcodec_decode_audio3(aCodecCtx, , ,&ptrPacket) < 0)
//            {
//                qDebug("Error decoding the Audiostream");
//                exit(-14);
//            }
            //encode the audio stream to target format
        }
    }

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

...