FFmpeg HLS выбирает потоки и извлекает только их данные

#ffmpeg #http-live-streaming #libavformat

#ffmpeg #http-прямая трансляция #libavformat

Вопрос:

При открытии потока HLS с использованием avformat_open_input извлекаются данные из всех потоков, и я хотел бы извлекать данные только из некоторых из них. Возможно ли это?

Рассмотрим следующий MWE:

 #include <libavformat/avformat.h>
int main(int argc, char **argv)
{
    AVFormatContext *inFmtCtx = NULL;
    AVPacket packet;
    const char *inUrl;
    int ret;

    if (argc < 2) { return -1; }
    inUrl = argv[1];

    if ((ret = avformat_open_input(amp;inFmtCtx, inUrl, NULL, NULL)) < 0)
        goto end;
    if ((ret = avformat_find_stream_info(inFmtCtx, NULL)) < 0)
        goto end;

    while (1) {
        ret = av_read_frame(inFmtCtx, amp;packet);
        if (ret < 0) break;

        // # Placeholder: Do Something # //
        printf("%i, ", packet.stream_index);

        av_packet_unref(amp;packet);
    }
end:
    avformat_close_input(amp;inFmtCtx);
    if (ret < 0 amp;amp; ret != AVERROR_EOF) {
        fprintf(stderr, "Error occurred: %sn", av_err2str(ret));
        return 1;
    }
    return 0;
}
 

Используя пример URL-адреса HLS «http://mcdn.daserste.de/daserste/de/master.m3u8 » (может быть заблокирован по геолокации), printf возвращает значения между 0 и 9 , указывая, что все 10 потоков (5 видео, 5 аудио) извлекаются.

Конечно, можно отбросить все, кроме выбранных, после того, как они были прочитаны, например, с помощью

     if(packet.stream_index != selectedVideoStreamId amp;amp; packet.stream_index != selectedAudioStreamId) {
        av_packet_unref(amp;packet);
        continue;
    }
 

Но можно ли настроить входной контекст / ffmpeg для извлечения только выбранных потоков, т. Е. Не Загружать все ненужные данные (невыбранные потоки)?

Ответ №1:

Вы можете отключить вариант HLS, отбросив все принадлежащие ему потоки:

 if ((ret = avformat_open_input(amp;inFmtCtx, inUrl, NULL, NULL)) < 0)
    goto end;

// disable all but the last stream
for (i = 0; i < inFmtCtx->nb_streams - 1;   i) {
    AVStream *st = inFmtCtx->streams[i];
    st->discard = AVDISCARD_ALL;
}

if ((ret = avformat_find_stream_info(inFmtCtx, NULL)) < 0)
    goto end;
 

Чтение вашего потока в течение нескольких секунд дает:

 stream=0 pkt_count=0
stream=1 pkt_count=0
stream=2 pkt_count=0
stream=3 pkt_count=0
stream=4 pkt_count=0
stream=5 pkt_count=0
stream=6 pkt_count=0
stream=7 pkt_count=0
stream=8 pkt_count=998
stream=9 pkt_count=937
 

Как вы можете видеть, он считывает два потока, соответствующих мультиплексированным аудио / видеопотокам в последнем списке воспроизведения, даже если был включен один поток. Если вам нужна более высокая степень детализации, вам придется изменить демультипликатор HLS.