繁体   English   中英

FFMPEG 库-将原始图像转码为 h264 流,并且输出文件不包含 pts 和 dts 信息

[英]FFMPEG library- transcode raw image to h264 stream, and the output file does not contains pts and dts info

我正在尝试使用 ffmpeg c++ 库将几个原始 yuyv 图像转换为 h264 流,图像来自内存并作为大约 24fps 的字符串传递,我按照以下步骤执行约定:

  1. 初始化 AVFormatContext,AVCodec,AVCodecContext 并创建新的 AVStream。 这一步主要参考ffmpeg-libav-tutorial ,AVFormatContext使用customize write_buffer()函数(参考simplest_ffmpeg_mem_handler
  2. 接收原始帧数据,设置宽度和高度(1920x1080),并设置 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;
  1. 将其从 yuyv 转换为 yuv422(因为 h264 不支持 yuyv)并将其大小从 1920x1080 调整为 640x480(因为我需要此分辨率输出),使用sws_scale()

  2. 使用avcodec_send_frame()avcodec_receive_packet()获取输出数据包。 设置output_packet duration 和 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(&output_packet);
  1. write_buffer()函数中,视频流输出被存储到字符串变量中,然后我用 ostream 将此字符串写入文件,并以 mp4 为后缀。

经过以上所有步骤,output.mp4无法播放, ffprobe output.mp4 -show_frames输出为( image ):

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

请注意,在步骤 4 中调用av_write_frame()之前和之后,传递的参数output_packet包含正确的 pts 和 dts 信息,我无法弄清楚为什么输出流会丢失这些信息。

我想通了,输出流是一个原始的h264流,我直接把这个流存到一个后缀为“.mp4”的文件中,所以它实际上不是一个正确的mp4文件。

然后将流存入output.h264文件,并使用 ffmpeg 将其转换为 mp4 文件: ffmpeg -framerate 24 -i output.h264 -c copy output.mp4 ,最后这个output.mp4包含正确的 pts 数据,可以播放.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM