ffmpeg tutorial1
来源:互联网 发布:ubuntu下php环境搭建 编辑:程序博客网 时间:2024/06/08 05:58
## An ffmpeg and SDL TutorialPage 1 2 3 4 5 6 7 End Prev Home Next  _place_holder;Text version## Tutorial 01: Making ScreencapsCode: tutorial01.c### OverviewMovie files have a few basic components. First, the file itself is called a**container**, and the type of container determines where the information inthe file goes. Examples of containers are AVI and Quicktime. Next, you have abunch of **streams**; for example, you usually have an audio stream and avideo stream. (A "stream" is just a fancy word for "a succession of dataelements made available over time".) The data elements in a stream are called**frames**. Each stream is encoded by a different kind of **codec**. The codecdefines how the actual data is COded and DECoded - hence the name CODEC.Examples of codecs are DivX and MP3. **Packets** are then read from thestream. Packets are pieces of data that can contain bits of data that aredecoded into raw frames that we can finally manipulate for our application.For our purposes, each packet contains complete frames, or multiple frames inthe case of audio.At its very basic level, dealing with video and audio streams is very easy: 10 OPEN video_stream FROM video.avi 20 READ packet FROM video_stream INTO frame 30 IF frame NOT COMPLETE GOTO 20 40 DO SOMETHING WITH frame 50 GOTO 20 Handling multimedia with ffmpeg is pretty much as simple as this program,although some programs might have a very complex "DO SOMETHING" step. So inthis tutorial, we're going to open a file, read from the video stream insideit, and our DO SOMETHING is going to be writing the frame to a PPM file.### Opening the FileFirst, let's see how we open a file in the first place. With ffmpeg, you haveto first initialize the library. #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <ffmpeg/swscale.h> ... int main(int argc, charg *argv[]) { av_register_all(); This registers all available file formats and codecs with the library so theywill be used automatically when a file with the corresponding format/codec isopened. Note that you only need to call av_register_all() once, so we do ithere in main(). If you like, it's possible to register only certain individualfile formats and codecs, but there's usually no reason why you would have todo that.Now we can actually open the file: AVFormatContext *pFormatCtx = NULL; // Open video file if(avformat_open_input(&pFormatCtx;, argv[1], NULL, 0, NULL)!=0) return -1; // Couldn't open file We get our filename from the first argument. This function reads the fileheader and stores information about the file format in the AVFormatContextstructure we have given it. The last three arguments are used to specify thefile format, buffer size, and format options, but by setting this to NULL or0, libavformat will auto-detect these.This function only looks at the header, so next we need to check out thestream information in the file.: // Retrieve stream information if(avformat_find_stream_info(pFormatCtx, NULL)<0) return -1; // Couldn't find stream information This function populates `pFormatCtx->streams` with the proper information. Weintroduce a handy debugging function to show us what's inside: // Dump information about file onto standard error av_dump_format(pFormatCtx, 0, argv[1], 0); Now `pFormatCtx->streams` is just an array of pointers, of size`pFormatCtx->nb_streams`, so let's walk through it until we find a videostream. int i; AVCodecContext *pCodecCtxOrig = NULL; AVCodecContext *pCodecCtx = NULL; // 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; The stream's information about the codec is in what we call the "codeccontext." This contains all the information about the codec that the stream isusing, and now we have a pointer to it. But we still have to find the actualcodec and open it: AVCodec *pCodec = NULL; // 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 } // Copy context pCodecCtx = avcodec_alloc_context3(pCodec); if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) { fprintf(stderr, "Couldn't copy codec context"); return -1; // Error copying codec context } // Open codec if(avcodec_open2(pCodecCtx, pCodec)<0) return -1; // Could not open codec Note that we must not use the AVCodecContext from the video stream directly!So we have to use avcodec_copy_context() to copy the context to a new location(after allocating memory for it, of course).### Storing the DataNow we need a place to actually store the frame: AVFrame *pFrame = NULL; // Allocate video frame pFrame=av_frame_alloc(); Since we're planning to output PPM files, which are stored in 24-bit RGB,we're going to have to convert our frame from its native format to RGB. ffmpegwill do these conversions for us. For most projects (including ours) we'regoing to want to convert our initial frame to a specific format. Let'sallocate a frame for the converted frame now. // Allocate an AVFrame structure pFrameRGB=av_frame_alloc(); if(pFrameRGB==NULL) return -1; Even though we've allocated the frame, we still need a place to put the rawdata when we convert it. We use `avpicture_get_size` to get the size we need,and allocate the space manually: uint8_t *buffer = NULL; int numBytes; // 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)); `av_malloc` is ffmpeg's malloc that is just a simple wrapper around mallocthat makes sure the memory addresses are aligned and such. It will _not_protect you from memory leaks, double freeing, or other malloc problems.Now we use avpicture_fill to associate the frame with our newly allocatedbuffer. About the AVPicture cast: the AVPicture struct is a subset of theAVFrame struct - the beginning of the AVFrame struct is identical to theAVPicture struct. // 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); Finally! Now we're ready to read from the stream!### Reading the DataWhat we're going to do is read through the entire video stream by reading inthe packet, decoding it into our frame, and once our frame is complete, wewill convert and save it. struct SwsContext *sws_ctx = NULL; int frameFinished; AVPacket packet; // initialize SWS context for software scaling sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL ); 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 sws_scale(sws_ctx, (uint8_t const * 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;); } **A note on packets**Technically a packet can contain partial frames or other bits of data, butffmpeg's parser ensures that the packets we get contain either complete ormultiple frames.The process, again, is simple: `av_read_frame()` reads in a packet and storesit in the `AVPacket` struct. Note that we've only allocated the packetstructure - ffmpeg allocates the internal data for us, which is pointed to by`packet.data`. This is freed by the `av_free_packet()` later.`avcodec_decode_video()` converts the packet to a frame for us. However, wemight not have all the information we need for a frame after decoding apacket, so `avcodec_decode_video()` sets frameFinished for us when we have thenext frame. Finally, we use `sws_scale()` to convert from the native format(`pCodecCtx->pix_fmt`) to RGB. Remember that you can cast an AVFrame pointerto an AVPicture pointer. Finally, we pass the frame and height and widthinformation to our SaveFrame function.Now all we need to do is make the SaveFrame function to write the RGBinformation to a file in PPM format. We're going to be kind of sketchy on thePPM format itself; trust us, it works. 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); } We do a bit of standard file opening, etc., and then write the RGB data. Wewrite the file one line at a time. A PPM file is simply a file that has RGBinformation laid out in a long string. If you know HTML colors, it would belike laying out the color of each pixel end to end like `#ff0000#ff0000`....would be a red screen. (It's stored in binary and without the separator, butyou get the idea.) The header indicated how wide and tall the image is, andthe max size of the RGB values.Now, going back to our main() function. Once we're done reading from the videostream, we just have to clean everything up: // Free the RGB image av_free(buffer); av_free(pFrameRGB); // Free the YUV frame av_free(pFrame); // Close the codecs avcodec_close(pCodecCtx); avcodec_close(pCodecCtxOrig); // Close the video file avformat_close_input(&pFormatCtx;); return 0; You'll notice we use av_free for the memory we allocated withavcode_alloc_frame and av_malloc.That's it for the code! Now, if you're on Linux or a similar platform, you'llrun: gcc -o tutorial01 tutorial01.c -lavutil -lavformat -lavcodec -lz -lavutil -lm If you have an older version of ffmpeg, you may need to drop -lavutil: gcc -o tutorial01 tutorial01.c -lavformat -lavcodec -lz -lm Most image programs should be able to open PPM files. Test it on some moviefiles._**>>** Tutorial 2: Outputting to the Screen_* * *Function ReferenceData Referenceemail:dranger at gmail dot comBack to dranger.comThis work is licensed under the Creative Commons Attribution-Share Alike 2.5License. To view a copy of this license, visithttp://creativecommons.org/licenses/by-sa/2.5/ or send a letter to CreativeCommons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. Code examples are based off of FFplay, Copyright (c) 2003 Fabrice Bellard, anda tutorial by Martin Bohme.//////////////////////////////////////////////////////////////////////////////////////////// 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// With updates from https://github.com/chelyaev/ffmpeg-tutorial// Updates tested on:// LAVC 54.59.100, LAVF 54.29.104, LSWS 2.1.101 // on GCC 4.7.2 in Debian February 2015// 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 -lswscale -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 <stdlib.h>#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>#include <libswscale/swscale.h>#include <libavutil/mem.h>// compatibility with newer API//#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)#define av_frame_alloc avcodec_alloc_frame#define av_frame_free avcodec_free_frame//#endifvoid 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[]) { // Initalizing these to NULL prevents segfaults! AVFormatContext *pFormatCtx = NULL; int i, videoStream; AVCodecContext *pCodecCtxOrig = NULL; AVCodecContext *pCodecCtx = NULL; AVCodec *pCodec = NULL; AVFrame *pFrame = NULL; AVFrame *pFrameRGB = NULL; AVPacket packet; int frameFinished; int numBytes; uint8_t *buffer = NULL; struct SwsContext *sws_ctx = NULL; if(argc < 2) { printf("Please provide a movie file\n"); return -1; } // Register all formats and codecs //这一步应该会关键,会注册ffmpeg支持的所有的编解码器 av_register_all(); // Open video file //调用ffmpeg特定的打开函数,会得到一个格式上下文,在格式上下文中将获得文件的头信息, //文件大小,编码格式等重要信息。 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 //获取该视频流的编码器上下文,编码器上下文中包含了跟编码相关的一些信息。 pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec; // Find the decoder for the video stream //根据流的编码id找到相应的解码器。 pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id); if(pCodec==NULL) { fprintf(stderr, "Unsupported codec!\n"); return -1; // Codec not found } // Copy context //分配一下编码器上下文。 pCodecCtx = avcodec_alloc_context3(pCodec); //复制一个由ffmpeg内部维护的编码器上下文,就是复制一下而已。 if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) { fprintf(stderr, "Couldn't copy codec context"); return -1; // Error copying codec context } // Open codec //打开编解码器,打开后,相关的句柄等保存在编解码器上下文中。 if(avcodec_open2(pCodecCtx, pCodec, NULL)<0) return -1; // Could not open codec // Allocate video frame //动态分配一下帧空间用于存储数据。 pFrame=av_frame_alloc(); // Allocate an AVFrame structure //再分配一个用于存储转换为RGB的数据。 pFrameRGB=av_frame_alloc(); 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 //这个是绑定pFrameRGB跟一个缓冲区, //前面使用pFrameRGB=av_frame_alloc()申请时,只是申请一个表面的结构体, //内部的缓冲区指针指向的空间还是NULL。 //但是我们要使用pFrameRGB保存数据,所以我们使用avpicture_fill来进行绑定。 //泥玛,这是网上找的答案。StackOverflow上一个老外回答的。 avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height); // initialize SWS context for software scaling //获取一个软件绽放上下文,用于一会儿绽放图像。 sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_RGB24, SWS_BILINEAR, NULL, NULL, NULL ); // Read frames and save first five frames to disk i=0; //泥玛,这里没有搞明白,为什么读取帧,要从格式上下文中读呢? //不过经过试验,的确是把avi中的前5帧保存成了ppm,还能查看呢。 //每次调用这句,ffmpeg就将一帧或几帧完整的数据放进packet中了。 while(av_read_frame(pFormatCtx, &packet)>=0) { // Is this a packet from the video stream? if(packet.stream_index==videoStream) { // Decode video frame //这里就是将AVPacket中的数据解码后放在AVFrame中。智能呀?还会告诉我们是否解码完毕呀? //应该就是一个返回值,表示解码成功或失败呀! avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); // Did we get a video frame? if(frameFinished) { // Convert the image from its native format to RGB //将pFrame中的数据软件绽放到指定的大小并存储在pFrameRGB中。 sws_scale(sws_ctx, (uint8_t const * 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_frame_free(&pFrameRGB); // Free the YUV frame av_frame_free(&pFrame); // Close the codecs avcodec_close(pCodecCtx); avcodec_close(pCodecCtxOrig); // Close the video file avformat_close_input(&pFormatCtx); return 0;}shell.albert@yantai:~/temporary> gcc tutorial01.c -I /home/shell.albert/libffmpeg/include -L /home/shell.albert/libffmpeg/lib -lavformat -lavcodec -lz -lm -lswscale -lavutil -o tutorial01.bintutorial01.c: In function ‘main’:tutorial01.c:137:3: warning: ‘avcodec_alloc_frame’ is deprecated (declared at /home/shell.albert/libffmpeg/include/libavcodec/avcodec.h:3422) [-Wdeprecated-declarations] pFrame=av_frame_alloc(); ^tutorial01.c:141:3: warning: ‘avcodec_alloc_frame’ is deprecated (declared at /home/shell.albert/libffmpeg/include/libavcodec/avcodec.h:3422) [-Wdeprecated-declarations] pFrameRGB=av_frame_alloc(); ^tutorial01.c:211:3: warning: ‘avcodec_free_frame’ is deprecated (declared at /home/shell.albert/libffmpeg/include/libavcodec/avcodec.h:3447) [-Wdeprecated-declarations] av_frame_free(&pFrameRGB); ^tutorial01.c:214:3: warning: ‘avcodec_free_frame’ is deprecated (declared at /home/shell.albert/libffmpeg/include/libavcodec/avcodec.h:3447) [-Wdeprecated-declarations] av_frame_free(&pFrame); ^shell.albert@yantai:~/temporary> shell.albert@yantai:~/temporary> ./tutorial01.bin zsy.avi Input #0, avi, from 'zsy.avi': Metadata: encoder : Lavf55.33.100 Duration: 00:03:20.03, start: 0.000000, bitrate: 479 kb/s Stream #0:0: Video: mpeg4 (Simple Profile) (FMP4 / 0x34504D46), yuv420p, 352x288 [SAR 1:1 DAR 11:9], 25 tbr, 25 tbn, 25 tbc Stream #0:1: Audio: ac3 ([0] [0][0] / 0x2000), 44100 Hz, stereo, fltp, 64 kb/s
0 0
- ffmpeg tutorial1
- 【Django tutorial1】
- ffmepg tutorial1
- Tutorial1 Open a window
- RCP复习:Rich Client Tutorial1
- Android opencv tutorial1相关问题
- pomelo(四) tutorial1 分布式聊天
- 翻译:Tutorial1:透明面板(LinearLayout)定义
- GLSL TUTORIAL1 Loading, Compiling and Linking OGLSL Programs
- DirectX9 SDK Samples(1) Tutorial1-Creating a device
- FFmpeg
- FFMPEG
- ffmpeg
- ffmpeg
- ffmpeg
- FFmpeg
- ffmpeg
- ffmpeg
- 解决phpmyadmin上传文件大小的限制
- Android Virtual Devices
- Adaboost 算法的原理与推导
- Stream自行总结的技巧,如果设置一个字节数组接收一个未知长度的流Stream
- 《学生在线学习系统》开发心得
- ffmpeg tutorial1
- 二、使用find和xargs
- 黑马程序员——Java基础---接口和多态
- 小胖说事12--------iOS App集成Apple Pay教程(附示例代码)
- 进程和线程的联系和区别 ,抽象类与接口的区别
- 用Struts2写的第一个"Hello,World!"
- PHP中定义数组的三种方式
- __super
- POJ 1364-King(差分约束系统)