Когда я запускаю свой демонстрационный код, я получаю следующие предупреждения при тестировании его на веб-видео:
[opus @ 0x5ec0fc1b4580] Could not update timestamps for skipped samples.
[opus @ 0x5ec0fc1b4580] Could not update timestamps for discarded samples.
Но это касается не только WebM, я также получаю это предупреждение при работе с mp4:
[aac @ 0x61326fb83700] Could not update timestamps for skipped samples.
Я знаю, что получаю предупреждения, потому что ffmpeg, должно быть, пропускает пакеты, но понятия не имею, почему. Почему мы пропускаем пакеты (и если проблема не в этом, то в чем) и как мы можем решить эту проблему?
Вот мой код для контекста:
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
int main()
{
int ret = 0;
const AVCodec* codec;
AVFormatContext* fmt_ctx = avformat_alloc_context();
const char* file2 = "/home/aabiji/Videos/sync-test.webm";
if ((ret = avformat_open_input(&fmt_ctx, file2, NULL, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Couldn't open input file\n");
return -1;
}
ret = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Couldn't find a media stream\n");
return -1;
}
int stream_index = ret;
AVStream* media = fmt_ctx->streams[stream_index];
AVCodecContext* codec_context = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(codec_context, media->codecpar) < 0) {
return -1;
}
if ((ret = avcodec_open2(codec_context, codec, NULL)) < 0) {
av_log(NULL, AV_LOG_ERROR, "Couldn't open media decoder\n");
return -1;
}
AVPacket* packet = av_packet_alloc();
AVFrame* frame = av_frame_alloc();
while ((ret = av_read_frame(fmt_ctx, packet)) >= 0) {
if (packet->stream_index != stream_index) {
continue;
}
ret = avcodec_send_packet(codec_context, packet);
if (ret < 0) {
break; // Error
}
while (ret >= 0) {
ret = avcodec_receive_frame(codec_context, frame);
if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) {
break;
} else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
break;
}
av_frame_unref(frame);
}
av_packet_unref(packet);
}
avcodec_flush_buffers(codec_context);
av_packet_unref(packet);
av_frame_free(&frame);
av_packet_free(&packet);
avcodec_free_context(&codec_context);
avformat_close_input(&fmt_ctx);
return 0;
}
ffmpeg не пропускает пакеты, по крайней мере, не так, как вы думаете. Пакеты от аудиокодера для таких кодеков, как MP3/AAC/Opus, взаимозависимы от соседних пакетов. Для начала и конца потока кодер вставляет для этой цели пустые выборки, которые должны быть пропущены (в начале) и отброшены (в конце) декодером.
Платформе avcodec необходимо заполнить два параметра для обновления временных меток для этих выборок — временную развертку пакета и частоту дискретизации звука. Последнее должно быть установлено декодером,
Для первого установите
codec_context->pkt_timebase = media->time_base;
перед вызовом avcodec_open2
Я понимаю. Большое спасибо!