想根据教程An ffmpeg and SDL Tutorial http://dranger.com/ffmpeg/tutorial01.html 学 习音视频解码,这个作为入门教程实在是太爽了,唯一有点不好的是,这个教程太老了使用现在的ffmpeg1.0的库是编译不过的(不过SDL变化比较 小)。所以修改代码使之符合现有的库,这样印象比较深刻。目前可以下到的ffmpeg的最新版本是ffmpeg-1.0,SDL的最新版本是SDL- 1.2.15.tar.gz,在ubuntu 12.04上进行开发。
一、环境搭建
下载ffmpeg-1.0.tar.bz2与SDL-1.2.15.tar.gz,并分别解压到/home/sun/code/目录下
ffmpeg --> 源码: /home/sun/code/ffmpeg-1.0 --> 安装: /home/sun/code/ffmpeg-1.0/install
SDL-1.2.15 -->源码: /home/sun/code/SDL-1.2.15 --> 安装: /home/sun/code/SDL-1.2.15/install
1.1 编译
SDL编译:
- sun@ubuntu:~/code/SDL-1.2.15$ ./configure --prefix=/home/sun/code/SDL-1.2.15/install
- sun@ubuntu:~/code/SDL-1.2.15$ make && make install
ffmpeg编译:
- sun@ubuntu:~/code/ffmpeg-1.0$ ./configure --prefix=/home/sun/code/ffmpeg-1.0/install --enable-memalign-hack --enable-shared --disable-yasm ;
- sun@ubuntu:~/code/ffmpeg-1.0$ make && make install
- 如果想在ffmpeg编译的同时也编译出ffplay,需要先安装SDL库
注意:av_read_frame读出的完整的帧,不是包,在函数内部已经保证了帧的完整性。对于视频,av_read_frame读出的就是完整的一帧视频,不会是半帧或多帧;对于音频,av_read_frame读出的可能是多帧,但也是完整的,不存在半帧的情况。
[参考]http://www.chinavideo.org/viewthread.php?tid=11104
二、Tutorial 01: Making Screencaps
1. 1screencaps.c
- // tutorial01.c
- // Code based on a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)
- // Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
-
- // A small sample program that shows how to use libavformat and libavcodec to
- // read video from a file.
- //
- // Use
- //
- // gcc -o tutorial01 tutorial01.c -lavformat -lavcodec -lz
- //
- // to build (assuming libavformat and libavcodec are correctly installed
- // your system).
- //
- // Run using
- //
- // tutorial01 myvideofile.mpg
- //
- // to write the first five frames from "myvideofile.mpg" to disk in PPM
- // format.
- #include <stdio.h>
- #include <libavformat/avformat.h>
- #include <libswscale/swscale.h>
-
- void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
- FILE *pFile;
- char szFilename[32];
- int y;
-
- // Open file
- sprintf(szFilename, "frame%d.ppm", iFrame);
- pFile=fopen(szFilename, "wb");
- if(pFile==NULL)
- return;
-
- // Write header
- fprintf(pFile, "P6\n%d %d\n255\n", width, height);
-
- // Write pixel data
- for(y=0; y<height; y++)
- fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
-
- // Close file
- fclose(pFile);
- }
-
- int main(int argc, char *argv[]) {
- AVFormatContext *pFormatCtx;
- int i, videoStream;
- AVCodecContext *pCodecCtx;
- AVCodec *pCodec;
- AVFrame *pFrame;
- AVFrame *pFrameRGB;
- AVPacket packet;
- int frameFinished;
- int numBytes;
- uint8_t *buffer;
-
- if(argc < 2) {
- printf("Please provide a movie file\n");
- return -1;
- }
- // Register all formats and codecs
- av_register_all();
-
- pFormatCtx = avformat_alloc_context();
- // Open video file
- //if(av_open_input_file(&pFormatCtx, argv[1], NULL, 0, NULL)!=0)
- if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
- return -1; // Couldn't open file
-
- // Retrieve stream information
- if(avformat_find_stream_info(pFormatCtx,NULL)<0)
- return -1; // Couldn't find stream information
-
- // Dump information about file onto standard error
- av_dump_format(pFormatCtx, 0, argv[1], 0);
-
- // Find the first video stream
- videoStream=-1;
- for(i=0; i<pFormatCtx->nb_streams; i++)
- if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
- videoStream=i;
- break;
- }
- if(videoStream==-1)
- return -1; // Didn't find a video stream
-
- // Get a pointer to the codec context for the video stream
- pCodecCtx=pFormatCtx->streams[videoStream]->codec;
-
- // Find the decoder for the video stream
- pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
- if(pCodec==NULL) {
- fprintf(stderr, "Unsupported codec!\n");
- return -1; // Codec not found
- }
- // Open codec
- if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
- return -1; // Could not open codec
-
- // Allocate video frame
- pFrame=avcodec_alloc_frame();
-
- // Allocate an AVFrame structure
- pFrameRGB=avcodec_alloc_frame();
- if(pFrameRGB==NULL)
- return -1;
-
- // Determine required buffer size and allocate buffer
- numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width,
- pCodecCtx->height);
- buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
-
- // Assign appropriate parts of buffer to image planes in pFrameRGB
- // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
- // of AVPicture
- avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24,
- pCodecCtx->width, pCodecCtx->height);
-
- // Read frames and save first five frames to disk
- i=0;
- while(av_read_frame(pFormatCtx, &packet)>=0) {
- // Is this a packet from the video stream?
- if(packet.stream_index==videoStream) {
- // Decode video frame
- avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
-
- // Did we get a video frame?
- if(frameFinished) {
- // Convert the image from its native format to RGB
- //img_convert((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
- static struct SwsContext * img_convert_ctx;
- //img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 聽PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
- //sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 聽0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
-
- img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
- sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
- // Save the frame to disk
- if(++i<=5)
- SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height,
- i);
- }
- }
-
- // Free the packet that was allocated by av_read_frame
- av_free_packet(&packet);
- }
-
- // Free the RGB image
- av_free(buffer);
- av_free(pFrameRGB);
-
- // Free the YUV frame
- av_free(pFrame);
-
- // Close the codec
- avcodec_close(pCodecCtx);
-
- // Close the video file
- avformat_close_input(&pFormatCtx);
-
- return 0;
- }
2. Makefile
- CC=gcc
- CFLAGS=-g -I/home/sun/code/ffmpeg-1.0/install/include
- LDFLAGS = -L/home/sun/code/ffmpeg-1.0/install/lib/ -lavutil -lavformat -lavcodec -lavutil -lm -lswscale
- TARGETS=1screencaps
- all: $(TARGETS)
- 1screencaps:1screencaps.c
- $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
-
- clean:
- rm -rf $(TARGETS)
3. 要想运行还需要把运行时库的搜索路径加上去
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/sun/code/ffmpeg-1.0/install/lib/:/home/sun/code/SDL-1.2.15/install/lib
(wangcong02345) |