需要帮助,最近我正在使用ffmpeg libavcodec解码视频文件然后编码为H264并写入mp4媒体容器,最后媒体文件的持续时间为零,以下是我的代码工作流程:
AVFormatContext* input_format_context = NULL;
AVFormatContext* output_format_context = NULL;
AVIOContext* output_io_context = NULL;
AVCodecContext* input_codec_context = NULL;
AVCodecContext* output_codec_context = NULL;
AVCodec* codec = NULL;
AVStream* input_stream = NULL;
AVStream* output_stream = NULL;
AVFrame* frame = NULL;
int convert_init(const char* input_filename, const char* output_filename)
{
/** Allocate a new encode context */
avformat_open_input(&input_format_context,
input_filename, NULL, NULL);
/** Get information on the input file (number of streams etc.). */
avformat_find_stream_info(input_format_context, NULL);
/** Open the output file to write to it. */
avio_open(&output_io_context, output_filename,
AVIO_FLAG_WRITE);
/** Create a new format context for the output container format. */
output_format_context = avformat_alloc_context();
/** Associate the output file (pointer) with the container format context. */
output_format_context->pb = output_io_context;
/** Guess the desired container format based on the file extension. */
output_format_context->oformat = av_guess_format(NULL,
output_filename, NULL);
av_strlcpy((output_format_context)->filename, output_filename,
sizeof(output_format_context->filename));
/** stream0 is the video stream */
AVStream* input_stream = input_format_context->streams[0];
/**
* Init the input_codec_context
*/
/** Find a decoder for the audio stream. */
codec = avcodec_find_decoder(input_stream->codecpar->codec_id);
/** Allocate a new decode context */
input_codec_context = avcodec_alloc_context3(codec);
/** Initialize the stream parameters with demuxer information */
avcodec_parameters_to_context(input_codec_context,
input_stream->codecpar);
/** Open the decoder for the stream. */
avcodec_open2(input_codec_context, codec, NULL);
/**
* Create an output stream for writing encoded data
*
* AM I MISSING SOMETHING ?
*
*/
output_stream = avformat_new_stream(output_format_context, NULL);
/**
* Init the output_codec_context
*/
/** Find a encoder for the output video stream, using H264. */
codec = avcodec_find_encoder(AV_CODEC_ID_H264);
/** Allocate an encode context. */
output_codec_context = avcodec_alloc_context3(codec);
/**
* Setup encode context parameters.
*
* AM I MISSING SOMETHING ?
*
* */
output_codec_context->bit_rate = input_codec_context->bit_rate;
output_codec_context->width = input_codec_context->width;
output_codec_context->height = input_codec_context->height;
output_codec_context->time_base = (AVRational){1, 25};
output_codec_context->framerate = (AVRational){25, 1};
output_codec_context->gop_size = 10;
output_codec_context->max_b_frames = 1;
output_codec_context->pix_fmt = AV_PIX_FMT_YUV420P;
output_codec_context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
/** Setup output_stream codecpar. */
avcodec_parameters_from_context(output_stream->codecpar,
codec_context);
/** Alloc an av frame */
frame = av_frame_alloc();
}
void convert_it()
{
AVPacket input_packet;
AVPacket output_packet;
/** Write the media file container header */
avformat_write_header(output_format_context, NULL);
/**
* decode frames and encode to H264
* */
while (1) {
av_init_packet(&input_packet);
input_packet.data = NULL;
input_packet.size = 0;
av_init_packet(&output_packet);
output_packet.data = NULL;
output_packet.size = 0;
/** Read a frame to decode */
av_read_frame(input_format_context, &input_packet);
if (av_read_frame is end of file) {
break;
}
...
...
/** Decoding... */
avcodec_send_packet(input_codec_context, &input_packet);
...
...
/** Get a decoded frame */
avcodec_receive_frame(input_codec_context, frame);
...
...
/** Make the frame writable, is it necessary ?? */
av_frame_make_writable(frame);
/** Encode to H264 */
avcodec_send_frame(output_codec_context, frame);
...
...
/** Get a encoded packet */
avcodec_receive_packet(output_codec_context, &output_packet);
/**
* Write the packet to output.
* Here is the point! should I configure the parameters
* in packet such as 'pts', 'dts', 'duration', etc, if so,
* hwo? or I just directly write the packet into output?
*/
av_interleaved_write_frame(output_format_context, &packet);
}
/** Write the media file container trailer */
av_write_trailer(output_format_context);
}
int main() {
convert_init("./sample.avi", "./output.mp4");
convert_it();
}
使用VLC或QuickTime播放output.mp4文件,失败,导致文件时长为零,拖拽时间进度条时,可以清晰看到画面帧,看来编码包缓冲数据是正确的,但是时间戳是错误的,我在配置 output_stream 或数据包时是否遗漏了什么?以下是来自 ffprobe 的消息。
ffprobe output.mp4
ffprobe version 3.3.3 Copyright (c) 2007-2017 the FFmpeg developers
built with Apple LLVM version 8.1.0 (clang-802.0.42)
configuration: --enable-shared --enable-libmp3lame
libavutil 55. 58.100 / 55. 58.100
libavcodec 57. 89.100 / 57. 89.100
libavformat 57. 71.100 / 57. 71.100
libavdevice 57. 6.100 / 57. 6.100
libavfilter 6. 82.100 / 6. 82.100
libswscale 4. 6.100 / 4. 6.100
libswresample 2. 7.100 / 2. 7.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf57.71.100
Duration: 00:00:00.06, start: 0.000000, bitrate: 6902181 kb/s
Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 720x408 [SAR 1:1 DAR 30:17], 13929056 kb/s, 90k fps, 90k tbr, 90k tbn, 50 tbc (default)
Metadata:
handler_name : VideoHandler
最佳答案
您的问题可能是在复用过程中帧的时基错误。
根据格式,the muxer can change the stream timebase .
The stream timebase should be set to the timebase that the caller desires to use for this stream (note that the timebase actually used by the muxer can be different, as will be described later).
[...]
Do note that the timing information on the packets sent to the muxer must be in the corresponding AVStream's timebase. That timebase is set by the muxer (in the avformat_write_header() step) and may be different from the timebase requested by the caller.
因此,在编写帧之前,您必须将其时基从创建 FormatContext 时设置的理论时基转换为流实际使用的时基。为此,您可以使用 av_packet_rescale_ts功能。
前任:
av_packet_rescale_ts(
packet,
codec_contex->time_base, // your theoric timebase
format_context->streams[packet->stream_index]->time_base); // the actual timebase
关于ffmpeg - 使用ffmpeg libavcodec将视频流编码为H264,为什么持续时间为零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45997264/