4

我正在逐帧转码视频并使用 x264+ffmpeg 进行编码。原始视频播放良好,但我转码视频的前几帧显示灰色伪影。我知道这是因为时间压缩,这些伪影在几帧后消失了。

请看这两张图片,它们是第一帧和第二帧。第三帧正常(即没有灰色伪影,也没有像第二帧那样模糊) 第一帧 第二帧

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

编辑 - 更多细节

这是我正在做的更多细节。我使用 bit form differents 教程逐帧读取视频并将每一帧重新编码为新视频。我的编码参数如下:

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;
}
4

2 回答 2

1

您的问题很可能出在解码部分而不是编码中(x264 无法产生此类伪影)。如上所述,您似乎不是从关键帧开始解码(或者可能是您的流是开放式的,并且您没有丢弃第一个 B 帧)。

于 2013-02-03T22:04:37.363 回答
1

这是因为您的视频不是以 关键帧开头的。为了解决这个问题,我使用AviDemux。从 2.6 版开始

  • MP4 混音器
  • MP4v2 混音器

并且可能更多支持没有关键帧的视频。

于 2013-02-03T20:32:34.243 回答