Путаница с PTS в видеофайлах и медиапотоках

Возможно ли, что PTS определенного кадра в файле отличается от PTS того же кадра в том же файле во время его потоковой передачи?

Когда я читаю кадр с помощью av_read_frame, я сохраняю видеопоток в AVStream. После декодирования кадра с помощью avcodec_decode_video2 я сохраняю отметку времени этого кадра в int64_t, используя av_frame_get_best_effort_timestamp. Теперь, если программа получает входные данные из файла, я получаю метку времени, отличную от того, когда я передаю входные данные (из того же файла) в программу.

Чтобы изменить тип ввода, я просто меняю аргумент argv с «/path/to/file.mp4» на что-то вроде «udp://localhost:1234», затем я передаю файл с помощью ffmpeg в командной строке: «ffmpeg -re -i /путь/к/файлу.mp4 -f mpegts udp://localhost:1234". Может ли это быть из-за того, что аргументы "-f mpegts" изменяют некоторые характеристики носителя?

Ниже мой код (упрощенный). Прочитав архивы списка рассылки ffmpeg, я понял, что time_base, который я ищу, находится в AVStream, а не в AVCodecContext. Вместо использования av_frame_get_best_effort_timestamp я также пытался использовать package.pts, но результаты не меняются. Мне нужны метки времени, чтобы иметь представление о номере кадра в получаемом потоковом видео. Я был бы очень признателен за любую помощь.

//..
//argv[1]="/file.mp4";
argv[1]="udp://localhost:7777";
// define AVFormatContext, AVFrame, etc.
// register av, avcodec, avformat_network_init(), etc.
avformat_open_input(&pFormatCtx, argv, NULL, NULL);
avformat_find_stream_info(pFormatCtx, NULL);
// find the video stream...
// pointer to the codec context...
// open codec...
pFrame=av_frame_alloc();
while(av_read_frame(pFormatCtx, &packet)>=0) {
        AVStream *strem = pFormatCtx->streams[videoStream];
        if(packet.stream_index==videoStream) {
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
            if(frameFinished) {
                int64_t perts = av_frame_get_best_effort_timestamp(pFrame);
                if (isMyFrame(pFrame)){
                     cout << perts*av_q2d(strem->time_base) << "\n";
                }
             }
}
//free allocated space
}
//..

person user2452253    schedule 07.11.2014    source источник


Ответы (1)


Временные метки хранятся на уровне контейнера, поэтому изменение контейнера может привести к изменению временных меток. Кроме того, TS хранит метку времени для каждого кадра (на основе тактовой частоты 90 кГц). MP4 хранит только длительность кадров с предполагаемым временем начала, равным 0 (это усложняется с bframes, поскольку первая PTS равна нулю, а первая DTS равна ‹ 0). Таким образом, чтобы получить отметку времени, добавляются все длительности кадров. MP4 также позволяет установить тактовую частоту. Часто это 1001/3000 тиков в секунду для 29,97 кадров в секунду, но его можно установить на что угодно. поэтому av_frame_get_best_effort_timestamp возвращает вам тики в единицах codec->stream_base. Для кодека TS->stream_base всегда 1/90000

person szatmary    schedule 07.11.2014
comment
Большое спасибо, очень информативно. В этом случае я предполагаю, что аргументы -f mpegts в потоковой команде изменяют контейнер на лету, верно? - person user2452253; 10.11.2014