#c #video #ffmpeg
#c #Видео #ffmpeg
Вопрос:
Я пытаюсь с помощью библиотеки ffmpeg c преобразовать несколько необработанных изображений yuyv в поток h264, изображение поступает из памяти и передается в виде строки со скоростью около 24 кадров в секунду, я выполняю соглашение следующим образом:
- инициализируйте AVFormatContext, AVCodec, AVCodecContext и создайте новый AVStream. на этом шаге я в основном ссылаюсь на ffmpeg-libav-tutorial, а AVFormatContext использует
write_buffer()
функцию настройки (см. simplest_ffmpeg_mem_handler) - получите необработанные данные кадра, установите ширину и высоту (1920×1080), а также установите pts и dts. здесь я вручную устанавливаю выходной fps равным 24 и использую глобальный счетчик для подсчета количества кадров, и pts вычисляется этим счетчиком, фрагментом кода (
video_avs
является AVStream,output_fps
равен 24 иtime_base
равен 1/24):
input_frame->width = w; // 1920
input_frame->height = h; // 1080
input_frame->pkt_dts = input_frame->pts = global_pts;
global_pts = video_avs->time_base.den/video_avs->time_base.num / output_fps.num * output_fps.den;
-
преобразуйте его из yuyv в yuv422 (потому что h264 не поддерживает yuyv) и измените его размер с 1920×1080 до 640×480 (потому что мне нужен вывод с таким разрешением), используйте
sws_scale()
-
используйте
avcodec_send_frame()
иavcodec_receive_packet()
для получения выходного пакета. установитеoutput_packet
длительность и stream_index, затем используйтеav_write_frame()
для записи данных кадра.
AVPacket *output_packet = av_packet_alloc();
int response = avcodec_send_frame(encoder->video_avcc, frame);
while (response >= 0) {
response = avcodec_receive_packet(encoder->video_avcc, output_packet); // !! here output_packet.size is calculated
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
break;
}
else if (response < 0) {
printf("Error while sending packet to decoder"); // ??av_err2str(response)会报错
return response;
}
// duration = next_pts - this_pts = timescale / fps = 1 / timebase / fps
output_packet->duration = (encoder->video_avs->time_base.den / encoder->video_avs->time_base.num) / (output_fps.num / output_fps.den);
output_packet->stream_index = 0;
int response = av_write_frame(encoder->avfc, output_packet); // packet order are not ensure
if (response != 0) { printf("Error %d while receiving packet from decoder", response); return -1;}
}
av_packet_unref(output_packet);
av_packet_free(amp;output_packet);
- в
write_buffer()
функции вывод видеопотока сохраняется в строковую переменную, а затем я записываю эту строку в файл с ostream и суффиксом mp4.
после всех вышеуказанных шагов вывод.mp4 не может быть воспроизведен, ffprobe output.mp4 -show_frames
вывод (изображение):
Input #0, h264, from '/Users/ming/code/dev/haomo/output.mp4':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (High 4:2:2), yuv422p(progressive), 640x480, 24.92 fps, 24 tbr, 1200k tbn, 48 tbc
[FRAME]
media_type=video
stream_index=0
key_frame=1
pkt_pts=N/A
pkt_pts_time=N/A
pkt_dts=N/A
pkt_dts_time=N/A
best_effort_timestamp=N/A
best_effort_timestamp_time=N/A
Обратите внимание, что до и после вызова av_write_frame()
на шаге 4 переданный аргумент output_packet
содержит правильную информацию о pts и dts, я не могу понять, почему выходной поток потерял эту информацию.
Ответ №1:
Я понимаю, что выходной поток представляет собой необработанный поток h264, и я напрямую сохраняю этот поток в файл с суффиксом «.mp4», так что на самом деле это неправильный файл mp4.
Затем он сохраняет поток в output.h264
файл и использует ffmpeg для преобразования его в файл mp4: ffmpeg -framerate 24 -i output.h264 -c copy output.mp4
, наконец, он output.mp4
содержит правильные данные pts и может быть воспроизведен.