【问题标题】:FFMPEG decoding artifacts between keyframes关键帧之间的 FFMPEG 解码伪影
【发布时间】:2014-01-17 15:11:46
【问题描述】:

我目前在使用 ffmpegs api 解码视频时遇到伪影。在我认为是中间帧的情况下,伪影仅从帧中的主动运动中缓慢构建。这些工件构建 50-100 帧,直到我假设一个关键帧重置它们。然后帧被正确解码,工件继续构建。

困扰我的一件事是我有一些 30fps(h264) 的视频样本可以正常工作,但我所有的 60fps 视频(h264) 都遇到了这个问题。

我目前没有足够的声望来发布图片,因此希望此链接能够正常工作。 http://i.imgur.com/PPXXkJc.jpg

int numBytes;
int frameFinished;
AVFrame* decodedRawFrame;
AVFrame* rgbFrame;

    //Enum class for decoding results, used to break decode loop when a frame is gathered
DecodeResult retResult = DecodeResult::Fail;

decodedRawFrame = av_frame_alloc();
rgbFrame = av_frame_alloc();
if (!decodedRawFrame) {
    fprintf(stderr, "Could not allocate video frame\n");
    return DecodeResult::Fail;
}

numBytes = avpicture_get_size(PIX_FMT_RGBA, mCodecCtx->width,mCodecCtx->height);
uint8_t* buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));

avpicture_fill((AVPicture *) rgbFrame, buffer, PIX_FMT_RGBA, mCodecCtx->width, mCodecCtx->height);

AVPacket packet;

while(av_read_frame(mFormatCtx, &packet) >= 0 && retResult != DecodeResult::Success)
{
    // Is this a packet from the video stream?
    if (packet.stream_index == mVideoStreamIndex)
    {
        // Decode video frame
        int decodeValue = avcodec_decode_video2(mCodecCtx, decodedRawFrame, &frameFinished, &packet);

        // Did we get a video frame?
        if (frameFinished)// && rgbFrame->pict_type != AV_PICTURE_TYPE_NONE )
        {
            // Convert the image from its native format to RGB
            int SwsFlags = SWS_BILINEAR;
            // Accurate round clears up a problem where the start
                            // of videos have green bars on them
            SwsFlags |= SWS_ACCURATE_RND;
            struct SwsContext *ctx = sws_getCachedContext(NULL, mCodecCtx->width, mCodecCtx->height, mCodecCtx->pix_fmt, mCodecCtx->width, mCodecCtx->height, 
                PIX_FMT_RGBA, SwsFlags, NULL, NULL, NULL);
            sws_scale(ctx, decodedRawFrame->data, decodedRawFrame->linesize, 0, mCodecCtx->height, rgbFrame->data, rgbFrame->linesize);

            //if(count%5 == 0 && count < 105)
            //  DebugSavePPMImage(rgbFrame, mCodecCtx->width, mCodecCtx->height, count);

            ++count;
            // Viewable frame is a struct to hold buffer and frame together in a queue
            ViewableFrame frame;
            frame.buffer = buffer;
            frame.frame = rgbFrame;
            mFrameQueue.push(frame);


            retResult = DecodeResult::Success;

            sws_freeContext(ctx);
        }
    }

    // Free the packet that was allocated by av_read_frame
    av_free_packet(&packet);
}

// Check for end of file leftover frames
if(retResult != DecodeResult::Success)
{
    int result = av_read_frame(mFormatCtx, &packet);
    if(result < 0)
        isEoF = true;
    av_free_packet(&packet); 
}   

// Free the YUV frame
av_frame_free(&decodedRawFrame);

我正在尝试构建解码帧的队列,然后根据需要使用和释放。我的帧分离是否导致中间帧解码不正确?一旦我成功收集了一帧,我也会打破解码循环(Decode::Success,我见过的大多数示例都倾向于循环播放整个视频。

所有编解码器内容、视频流信息和格式上下文都完全按照https://github.com/chelyaev/ffmpeg-tutorial/blob/master/tutorial01.c 的主函数中所示设置

任何建议将不胜感激。

【问题讨论】:

  • 尽职调查:这些问题视频是否可以与其他播放器正确解码?如果不是,则流可能已损坏。 FFmpeg 自己的播放器 (ffplay) 是否正确显示帧?另外,这些视频是从哪里来的?你知道用的是什么编码器吗?
  • 您的解码代码对我来说看起来不错。我同意上面的迈克。请注意,视频解码器根本不关心 FPS——只有视频播放器才应该关心——所以如果你每秒有 1 帧或 1200 帧,这无关紧要。

标签: c++ video ffmpeg decoding


【解决方案1】:

如果有人发现自己处于相似位置,供参考。显然,对于一些旧版本的 FFMPEG,使用 sws_scale 转换图像而不改变最终帧的实际尺寸时会出现问题。相反,如果您使用以下方法为 SwsContext 创建一个标志:

int SwsFlags = SWS_BILINEAR; //无论你想要什么 SwsFlags |= SWS_ACCURATE_RND; // 在底层强制 ffmpeg 使用与缩放相同的逻辑

SWS_ACCURATE_RND 有性能损失,但对于普通视频,它可能不那么明显。这将移除纹理边缘的绿色飞溅或绿色条(如果存在)。

我要感谢 Multimedia Mike 和 George Y,他们也是正确的,因为我解码帧的方式没有正确保存数据包,这就是导致视频伪像从之前的帧构建的原因。

【讨论】:

  • 如果能提供更多细节会更好,包括关于如何正确保存数据包。
猜你喜欢
  • 2020-10-06
  • 1970-01-01
  • 2019-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-19
  • 2018-11-05
  • 2012-12-22
相关资源
最近更新 更多