视频编码和关键帧

时间:2013-02-03 19:16:36

标签: encoding ffmpeg x264 keyframe

我逐帧转码视频并使用x264 + ffmpeg进行编码。原始视频播放效果很好,但我的转码视频的前几帧显示灰色的人工制品。据我所知,这是因为时间压缩,这些人工制品在几帧之后消失了。

参见这两张图片,它们是第一帧和第二帧。第三帧是正常的(即没有灰色伪像而不像第二帧那样模糊) First frame Second frame

如何强制第一帧成为关键帧(即在我的输出视频中完全编码),以便这些人工制品不显示?

修改 - 更多详情

以下是我正在做的更多细节。我使用位形式不同教程逐帧读取视频,并将每个帧重新编码为新视频。我的编码参数如下:

avcodec_get_context_defaults3(c, *codec);
c->codec_id = codec_id;
c->bit_rate = output_bitrate;
/* Resolution must be a multiple of two. */
c->width    = output_width;
c->height   = output_height;
/* timebase: This is the fundamental unit of time (in seconds) in terms
 * of which frame timestamps are represented. For fixed-fps content,
 * timebase should be 1/framerate and timestamp increments should be
 * identical to 1. */
st->r_frame_rate.num = output_framerate_num;
st->r_frame_rate.den = output_framerate_den;
c->time_base.den = output_timebase_den;
c->time_base.num = output_timebase_num;
c->gop_size      = 3; /* emit one intra frame every twelve frames at most */
c->pix_fmt       = STREAM_PIX_FMT;
if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) {
    /* just for testing, we also add B frames */
    c->max_b_frames = 2;
}
if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) {
    /* Needed to avoid using macroblocks in which some coeffs overflow.
     * This does not happen with normal video, it just happens here as
     * the motion of the chroma plane does not match the luma plane. */
    c->mb_decision = 2;
}
c->max_b_frames = 2;
c->scenechange_threshold = 0;
c->rc_buffer_size = 0;
c->me_method = ME_ZERO;

然后我处理每一帧,可能在那里做错了。解码位:

while(av_read_frame(gFormatCtx, &packet)>=0) {
    // Is this a packet from the video stream?
    if(packet.stream_index==gVideoStreamIndex) {
        // Decode video frame
        avcodec_decode_video2(gVideoCodecCtx, pCurrentFrame, &frameFinished, &packet);
        // Did we get a video frame?
        if(frameFinished) {
            [...]
            if(firstPts == -999) /*Initial value*/
                firstPts = packet.pts;
            deltaPts = packet.pts - firstPts;
            double seconds = deltaPts*av_q2d(gFormatCtx->streams[gVideoStreamIndex]->time_base);
            [...]
            muxing_writeVideoFrame(pCurrentFrame, packet.pts);
        }
    }
}

实际写作:

int muxing_writeVideoFrame(AVFrame *frame, int64_t pts)
{
frameCount = frameCount +1;
if(frameCount > 0)
{
    if (video_st)
        video_pts = (double)video_st->pts.val * video_st->time_base.num /
                    video_st->time_base.den;
    else
        video_pts = 0.0;

    if (video_st && !(video_st && audio_st && audio_pts < video_pts))
    {
        frame->pts = pts;//av_rescale_q(frame_count, video_st->codec->time_base, video_st->time_base);
        write_video_frame(oc, video_st, frame);
    }
}

return 0;
}

static int write_video_frame(AVFormatContext *oc, AVStream *st, AVFrame *frame)
{
    int ret;
    static struct SwsContext *sws_ctx;
    //LOGI(10, frame_count);
    AVCodecContext *c = st->codec;

    /* encode the image */
    AVPacket pkt;
    int got_output;
    av_init_packet(&pkt);
    pkt.data = NULL;    // packet data will be allocated by the encoder
    pkt.size = 0;
ret = avcodec_encode_video2(c, &pkt, frame, &got_output);
if (ret < 0) {
    fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret));
    exit(1);
}
/* If size is zero, it means the image was buffered. */
if (got_output) {
    if (c->coded_frame->key_frame)
        pkt.flags |= AV_PKT_FLAG_KEY;
    pkt.stream_index = st->index;
    /* Write the compressed frame to the media file. */
    ret = av_interleaved_write_frame(oc, &pkt);
} else {
    ret = 0;
}

    if (ret != 0) {
        LOGI(10, av_err2str(ret));
        exit(1);
    }
    frame_count++;
    return got_output;
}

2 个答案:

答案 0 :(得分:1)

这是因为您的视频不以a开头 keyframe。要解决此问题,请使用AviDemux。从2.6版开始

  • MP4 Muxer
  • MP4v2 Muxer

并且可能更多支持在没有关键帧的情况下启动视频。

答案 1 :(得分:1)

您的问题最有可能在解码部分而非编码(x264无法产生此类工件)。如上所述,看起来你不是从关键帧开始解码(或者你的流可能是open-gop而你没有丢弃第一个B帧)。