ffmpeg教程二:屏幕显示

SDL and Video 显示图像的方法有很多,这里我们使用 SDL 。SDL 英文全称为 Simple Direct Layer 。是一个跨平台的多媒体库,也就是你可以在 windonws linuxe 和 mac 里面使用这个库。所谓的多媒体库,就是提供了图像显示,声音播放,和线程相关接口的库。在 linux 上安装这个库很简单,示例代码的 README 已经有写了。 SDL 提供了很多显示图片的方法,SDL显示图片是通过把数据显示在 YUV 层实现的。YUV 是显示原始数据的一种方法,类似于 RGB,通俗地说, Y 代表亮度系数, U 和 V 代表颜色系数。SDL的工作方式是把 YUV数据传进 YUV 层并显示。它接受4种 YUV 格式,但其中 YV12 是最快的。另一种格式叫 YUV420P 和 YV12 差不多,只是 U 和 V 调转了。420 的意思是每个样本的比例是 4:2:0 ,也就是每4个亮度分量共享一个颜色分量。这样可以节省带宽,而且人类对于颜色分量不太敏感,即使去掉几个也看不出差别。“P” 的意思是数据是 Y U V 在不同的数组中。ffmpeg 能够把图像转为 YUV420P, 其实很多视频已经使用这种格式存储图像,或者很容易就可以转为到这种格式。 现在如果想要显示图像,我们要把之前的代码中的 SaveFrame 函数替换掉。但是首先,我们先要知道怎么用 SDL 。 首先需要把库包含进来并初始化 SDL: :::c #include <SDL.h> #include <SDL_thread.h> if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); exit(1); } SDL_Init 告诉库我们先要用什么功能。SDL_GetError 显然是用来处理 debug 信息的函数。...

December 31, 2013

为android编译ffmpeg

之前的教程是在桌面系统上实现的,由于系统已经为我们提供好了相关的库,所以我们之需要调用库的接口就可以使用ffmpeg为我们提供的功能了。但是我们现在需要在android系统上面调用这些函数,ffmpeg没有为我们提供可在android上运行的动态链接库。这时候我们需要。 此次移植的是ffmpeg0.11.2,使用的编译工具是android提供的android-r8d,编译脚本与Android.mk参考了abitno。 First of the first,我们需要在ffmpeg主页下载源代码。到目前为止,ffmpeg的版本已经发展到了1.1.3,可我们的目标却是0.11.2,真是个固步自封的熊孩子。说话回来,我们不是在追求最新,只是追求可用。 ffmpeg的链接: http://www.ffmpeg.org/download.html,其实ffmpeg已经把代码托管到github,把github的版本库拉回来,想用哪个版本就切换到那个版本会更方便点。 ##config.h config.h是一个很重要的配置文件,但是这个文件不是手工编写或者默认提供,而是需要通过configure得到。configure又是如何使用的?ffmpeg源代码目录敲入命令./configure --help,可以列出configure的相关选项。下面我提供了一个脚本,里面记录了configure的选项,只要我们运行脚本,就会配置ffmpeg了。 :::sh #!/bin/sh ANDROID_NDK=/home/gavin/android-ndk-r8d SYSROOT=$ANDROID_NDK/platforms/android-14/arch-arm TOOLCHAIN=`echo $ANDROID_NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86` export PATH=$TOOLCHAIN/bin:$PATH FLAGS="--target-os=linux --cross-prefix=arm-linux-androideabi- --arch=arm --cpu=armv7-a " FLAGS="$FLAGS --sysroot=$SYSROOT" FLAGS="$FLAGS --disable-avdevice --disable-static --enable-shared --disable-ffplay --disable-doc --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-avfilter --disable-encoders --disable-muxers --disable-filters --disable-devices --enable-version3 --enable-asm --enable-neon " EXTRA_CFLAGS="-I$ANDROID_NDK/sources/cxx-stl/system/include" EXTRA_CFLAGS="$EXTRA_CFLAGS -fPIC -march=armv7-a -mfloat-abi=softfp -mfpu=neon" #EXTRA_CFLAGS="$EXTRA_CFLAGS -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16" EXTRA_LDFLAGS="-Wl,--fix-cortex-a8 -nostdlib" EXTRA_CXXFLAGS="-Wno-multichar -fno-exceptions -fno-rtti" ABI="armeabi-v7a" echo $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" > info.txt ./configure $FLAGS --extra-cflags="$EXTRA_CFLAGS" --extra-ldflags="$EXTRA_LDFLAGS" --extra-cxxflags="$EXTRA_CXXFLAGS" | tee configuration....

March 10, 2013

ffmpeg教程一:视频截图(Tutorial 01: Making Screencaps

教程原地址为:http://dranger.com/ffmpeg/tutorial01.html,本人只是做了翻译和部分接口更新工作,保证其能正常工作。需要做一些预备工作 :::java sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libavdevice-dev libavfilter-dev libavutil-dev libpostproc-dev 首先我们需要了解视频文件的一些基本概念,视频文件本身被称作容器,例如avi或者是quicktime,容器的类型确定了文件的信息。然后,容器里装的东西叫流(stream),通常包括视频流和音频流(“流”的意思其实就是“随着时间推移的一段连续的数据元素”)。流中的数据元素叫做“帧”。每个流由不同的编解码器来编码,编解码器定义了数据如何编码(COded)和解码(DECoded),所以叫做编解码器(CODEC)。编解码器的例子有Divx和mp3。包(Packets),是从流中读取的,通过解码器解包,得到原始的帧,我们便可以对这些数据进行播放等的处理。对于我们来说,每个包包含完整的帧,或者多个音频帧。 在初级的水平,处理音视频流是非常简单的: 从video.avi中获得视频流 从视频流中解包得到帧 如果帧不完整,重复第2步 对帧进行相关操作 重复第2步 用ffmpeg来处理多媒体就像上面的步骤那么简单,即使你的第4步可能很复杂。所以在本教程,我们先打开一个视频,读取视频流,获得帧,然后第4步是把帧数据存储为PPM文件。 ##打开文件 我们先来看一下怎么打开一个视频文件,首先把头文件包含进来 :::c #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> ... int main(int argc, char *argv[]){ av_register_all(); av_register_all只需要调用一次,他会注册所有可用的文件格式和编解码库,当文件被打开时他们将自动匹配相应的编解码库。如果你愿意,可以之注册个别的文件格式和编解码库。 现在我们真的要打开一个文件了 :::c AVFormatContext *pFormatCtx; if(av_open_input_file(&pFormatCtx,argv[1],NULL,0,NULL)!=0) return -1; 我们从传入的第一个参数获得文件路径,这个函数会读取文件头信息,并把信息保存在我们存入的pFormatCtx结构体当中。这个函数后面三个参数分别是指定文件格式,缓存大小,和格式化选项,当我们设置为NULL或0时,libavformat会自动完成这些工作。 这个函数仅仅是获得了头信息,下一步我们要得到流信息 :::c if(av_find_steam_info(pFormatCtx)<0) return -1 这个函数填充了pFormatCtx->streams流信息, 我们可以通过dump_format把信息打印出来 :::c dump_format(pFormatCtx, 0, argv[1], 0); pFromatCtx->streams只是大小为pFormateCtx->nb_streams的一系列的点,我们要从中得到视频流 :::c int i; AVCodecContext *pCodecCtx; // Find the first video stream videoStream=-1; for(i=0; i<pformatctx->nb_streams; i++) if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) { videoStream=i; break; } if(videoStream==-1) return -1; // Didn't find a video stream</pformatctx-></pre> // Get a pointer to the codec context for the video stream pCodecCtx=pFormatCtx->streams[videoStream]->codec; pCodecCtx包含了这个流在用的编解码的所有信息,但我们仍需要通过他获得特定的解码器然后打开他。...

January 17, 2013