Chinaunix首页 | 论坛 | 博客
  • 博客访问: 387918
  • 博文数量: 55
  • 博客积分: 1907
  • 博客等级: 上尉
  • 技术积分: 869
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-04 19:30
文章分类

全部博文(55)

文章存档

2011年(32)

2010年(23)

分类: 嵌入式

2011-02-14 21:25:20

Using libavformat and libavcodec: An Update
 
 
  (boehme@inb.uni-luebeckREMOVETHIS.de) July 21, 2004

Update (January 23 2009): By now, these articles are quite out of date... unfortunately, I haven't found the time to update them, but thankfully, others have jumped in. Stephen Dranger has , ryanfb of cryptosystem.org has an of the code, and David Hoerl has a .

Update (April 26, 2005): A reader informs me that to compile the example programs on Kanotix (a Debian derivative) and possibly Debian itself, the include directives for avcodec.h and avformat.h have to be prefixed with "ffmpeg", like this:

  1. #include <ffmpeg/avcodec.h>
  2. #include <ffmpeg/avformat.h>

Also, the library libdts has to be included when compiling the programs, like this:

  1. g++ -o avcodec_sample.0.4.9 avcodec_sample.0.4.9.cpp \ -lavformat -lavcodec -ldts -lz

A few months ago, I wrote an on using the libavformat and libavcodec libraries that come with . Since then, I have received a number of comments, and a new prerelease version of ffmpeg (0.4.9-pre1) has recently become available, adding support for seeking in video files, new file formats, and a simplified interface for reading video frames. These changes have been in the CVS for a while, but now is the first time we get to see them in a release. (Thanks by the way to Silviu Minut for sharing the results of long hours of studying the CVS versions of ffmpeg - his page with ffmpeg information and a demo program is .)

本文主要讲:

----------------------------------------------------------------------------------

In this article, I'll describe only the differences between the previous release (0.4.8) and the new one, so if you're new to libavformat / libavcodec, I suggest you read the original article first.

----------------------------------------------------------------------------------

First, a word about compiling the new release. On my compiler (gcc 3.3.1 on SuSE), I get an internal compiler error while compiling the source file ffv1.c. I suspect this particular version of gcc is a little flaky - I've had the same thing happen to me when compiling OpenCV - but at any rate, a quick fix is to compile this one file without optimizations. The easiest way to do this is to do a make, then when the build hits the compiler error, change to the libavcodec subdirectory (since this is where ffv1.c lives), copy the gcc command to compile ffv1.c from your terminal window, paste it back in, edit out the "-O3" compiler switch and then run gcc using that command. After that, you can change back to the main ffmpeg directory and restart make, and it should complete the build.

What's New?
ffmpeg0.4.9和0.4.8/earlier版本中两个函数的区别
new: av_read_frame()
old: av_read_packet()
---------------------------------------------------------------------------------

So what's new? From a programmer's point of view, the biggest change is probably the simplified interface for reading individual video frames from a video file. In ffmpeg 0.4.8 and earlier, data is read from the video file in packets using the routine av_read_packet(). Usually, the information for one video frame is spread out over several packets, and the situation is made even more complicated by the fact that the boundary between two video frames can come in the middle of two packets. Thankfully, ffmpeg 0.4.9 introduces a new routine called av_read_frame(), which returns all of the data for a video frame in a single packet. The old way of reading video data using av_read_packet() is still supported but deprecated - I say: good riddance.

---------------------------------------------------------------------------------------------

So let's take a look at how to access video data using the new API. In my original article (with the old 0.4.8 API), the main decode loop looked like this:

  1. while(GetNextFrame(pFormatCtx, pCodecCtx, videoStream, pFrame))
  2. {
  3.      img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame,
  4.          pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
  5.      // Process the video frame (save to disk etc.)
  6.      DoSomethingWithTheImage(pFrameRGB);
  7. }

GetNextFrame() is a helper routine that handles the process of assembling all of the packets that make up one video frame. The new API simplifies things to the point that we can do the actual reading and decoding of data directly in our main loop:

  1. while(av_read_frame(pFormatCtx, &packet)>=0)
  2. {
  3.     // Is this a packet from the video stream?
  4.     if(packet.stream_index==videoStream)
  5.     {
  6.          // Decode video frame
  7.          avcodec_decode_video(pCodecCtx, pFrame, &frameFinished, packet.data, packet.size);
  8.         // Did we get a video frame?
  9.         if(frameFinished)
  10.         {
  11.               // Convert the image from its native format to RGB
  12.               img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24,
  13.                 (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width,
  14.                    pCodecCtx->height);
  15.              // Process the video frame (save to disk etc.)
  16.              DoSomethingWithTheImage(pFrameRGB);
  17.          }
  18.      }
  19.      // Free the packet that was allocated by av_read_frame
  20.      av_free_packet(&packet);
  21.  }

At first sight, it looks as if things have actually gotten more complex - but that is just because this piece code does things that used to be hidden in the GetNextFrame() routine (checking if the packet belongs to the video stream, decoding the frame and freeing the packet). Overall, because we can eliminate GetNextFrame() completely, things have gotten a lot easier.

I've updated the to use the new API. Simply comparing the number of lines (222 lines for the old version vs. 169 lines for the new one) shows that the new API has simplified things considerably.

--------------------------------------------------------------------------------------------

Another important addition in the 0.4.9 release is the ability to seek to a certain timestamp in a video file. This is accomplished using the av_seek_frame() function, which takes three parameters: A pointer to the AVFormatContext, a stream index and the timestamp to seek to. The function will then seek to the first key frame before the given timestamp. All of this is from the documentation - I haven't gotten round to actually testing av_seek_frame() yet, so I can't present any sample code either. If you've used av_seek_frame() successfully, I'd be glad to hear about it.

--------------------------------------------------------------------------------------------

Frame Grabbing (Video4Linux and IEEE1394)
sent me some sample code that demonstrates how to grab frames from a Video4Linux or IEEE1394 video source using libavformat / libavcodec. For Video4Linux, the call to av_open_input_file() should be modified as follows:

  1. AVFormatParameters formatParams;
  2. AVInputFormat *iformat;
  3. formatParams.device = "/dev/video0";
  4. formatParams.channel = 0;
  5. formatParams.standard = "ntsc";
  6. formatParams.width = 640;
  7. formatParams.height = 480;
  8. formatParams.frame_rate = 29;
  9. formatParams.frame_rate_base = 1;
  10. filename = "";
  11. iformat = av_find_input_format("video4linux");
  12. av_open_input_file(&ffmpegFormatContext, filename, iformat, 0, &formatParams);

For IEEE1394, call av_open_input_file() like this:

  1. AVFormatParameters formatParams;
  2. AVInputFormat *iformat;
  3. formatParams.device = "/dev/dv1394";
  4. filename = "";
  5. iformat = av_find_input_format("dv1394");
  6. av_open_input_file(&ffmpegFormatContext, filename, iformat, 0, &formatParams);

If I come across additional interesting information about libavformat / libavcodec, I plan to publish it here. So, if you have any comments, please contact me at the address given at the top of this article.

Standard disclaimer: I assume no liability for the correct functioning of the code and techniques presented in this article.

 

阅读(2062) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~