首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >libavcodec,如何转码不同帧率的视频?

libavcodec,如何转码不同帧率的视频?
EN

Stack Overflow用户
提问于 2010-11-16 17:19:41
回答 1查看 3.6K关注 0票数 5

我通过v4l从摄像头抓取视频帧,我需要将它们转换为mpeg4格式,以便通过RTP连续流传输。

一切实际上都是“正常的”,但在重新编码时,我没有做到这一点:输入流产生15fps,而输出是25fps,并且每个输入帧都被转换成一个单一的视频对象序列(我通过对输出比特流的简单检查验证了这一点)。我猜接收器正确地解析了mpeg4比特流,但是RTP打包不知何故是错误的。我应该如何将编码的比特流分割成一个或多个AVPacket?也许我遗漏了显而易见的东西,我只需要寻找B/P帧标记,但我认为我没有正确使用encode API。

以下是我的代码摘录,基于可用的ffmpeg示例:

代码语言:javascript
复制
// input frame
AVFrame *picture;
// input frame color-space converted
AVFrame *planar;
// input format context, video4linux2
AVFormatContext *iFmtCtx;
// output codec context, mpeg4
AVCodecContext *oCtx;
// [ init everything ]
// ...
oCtx->time_base.num = 1;
oCtx->time_base.den = 25;
oCtx->gop_size = 10;
oCtx->max_b_frames = 1;
oCtx->bit_rate = 384000;
oCtx->pix_fmt = PIX_FMT_YUV420P;

for(;;)
{
  // read frame
  rdRes = av_read_frame( iFmtCtx, &pkt );
  if ( rdRes >= 0 && pkt.size > 0 )
  {
    // decode it
    iCdcCtx->reordered_opaque = pkt.pts;
    int decodeRes = avcodec_decode_video2( iCdcCtx, picture, &gotPicture, &pkt );
    if ( decodeRes >= 0 && gotPicture )
    {
      // scale / convert color space
      avpicture_fill((AVPicture *)planar, planarBuf.get(), oCtx->pix_fmt, oCtx->width, oCtx->height);
      sws_scale(sws, picture->data, picture->linesize, 0, iCdcCtx->height, planar->data, planar->linesize);
      // encode
      ByteArray encBuf( 65536 );
      int encSize = avcodec_encode_video( oCtx, encBuf.get(), encBuf.size(), planar );
      // this happens every GOP end
      while( encSize == 0 )
        encSize = avcodec_encode_video( oCtx, encBuf.get(), encBuf.size(), 0 );
      // send the transcoded bitstream with the result PTS
      if ( encSize > 0 )
        enqueueFrame( oCtx->coded_frame->pts, encBuf.get(), encSize );
    }
  }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-07-29 04:06:55

最简单的解决方案是使用两个线程。第一线程会做你问题中概述的所有事情(解码,缩放/颜色空间转换,编码)。部分转码的帧将被写入与第二线程共享的中间队列。在这种特定情况下(从较低比特率转换到较高比特率),该队列的最大长度将是1帧。第二个线程将从输入队列中读取循环帧,如下所示:

代码语言:javascript
复制
void FpsConverter::ThreadProc()
{

timeBeginPeriod(1);
DWORD start_time = timeGetTime();
int frame_counter = 0;
while(!shouldFinish()) {
    Frame *frame = NULL;
    DWORD time_begin = timeGetTime();
    ReadInputFrame(frame);
    WriteToOutputQueue(frame);
    DWORD time_end = timeGetTime();
    DWORD next_frame_time = start_time + ++frame_counter * frame_time;
    DWORD time_to_sleep = next_frame_time - time_end;
    if (time_to_sleep > 0) {
        Sleep(time_to_sleep);
    }
}
timeEndPeriod(1);
}

当CPU能力足够并且需要更高的保真度和平滑度时,您可以通过某种插值(类似于mpeg编解码器中使用的技术)计算输出帧,而不是只从一个帧计算输出帧。输出帧时间戳越接近输入帧时间戳,应该为该特定输入帧指定的权重就越多。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4192598

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档