如何在 IPHONE 下面用 FFMPEG 播放 H.264 流开发记录
下载最新的 ffmpeg, 我下的是 0.8.2
下载最新的 gas-preprocessor 脚本 (用来在 MAC OS X 下编译汇编代码的):
https://github.com/yuvi/gas-preprocessor
请将 gas-preprocessor.pl 脚本安装在 /usr/sbin 或者其他执行文件目录下, 并添加执行权限
分别使用下面的配置进行编译:
IOS4.3 armv7 版本 (iPhone 3Gs, iPhone4):
./configure --disable-doc --disable-ffmpeg --disable-ffplay --disable-ffserver --disable-avdevice --disable-swscale --disable-avfilter --disable-avformat --disable-debug --disable-encoders --enable-cross-compile --disable-decoders --disable-armv5te --enable-decoder=h264 --enable-pic --arch=arm --target-os=darwin --cc=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc --as='gas-preprocessor/gas-preprocessor.pl /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc' --sysroot=/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk --cpu=cortex-a8 --extra-cflags='-arch armv7' --extra-ldflags='-arch armv7 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk'
IOS4.3 armv6 版本 (iPhone 3G):
./configure --disable-doc --disable-ffmpeg --disable-ffplay --disable-ffserver --disable-avdevice --disable-swscale --disable-avfilter --disable-avformat --disable-debug --disable-encoders --enable-cross-compile --disable-decoders --disable-armv5te --enable-decoder=h264 --enable-pic --arch=arm --target-os=darwin --cc=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc --as='gas-preprocessor/gas-preprocessor.pl /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc' --sysroot=/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk --cpu=arm1176jzf-s --extra-cflags='-arch armv6' --extra-ldflags='-arch armv6 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk'
IOS4.3 i386 版本 (用于模拟器):
./configure --disable-doc --disable-ffmpeg --disable-ffplay --disable-ffserver --disable-avdevice --disable-swscale --disable-avfilter --disable-avformat --disable-debug --disable-encoders --enable-cross-compile --disable-decoders --disable-armv5te --enable-decoder=h264 --enable-pic --cc=/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc --as='gas-preprocessor/gas-preprocessor.pl /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/gcc' --extra-ldflags=-L/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk/usr/lib/system --sysroot=/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.3.sdk --target-os=darwin --arch=i386 --cpu=i386 --extra-cflags='-arch i386' --extra-ldflags='-arch i386'
将上述分别编译出来的库, 打包成一个统一的版本的方法:
lipo -create -arch armv6 armv6/libavcodec.a -arch armv7 armv7/libavcodec.a -arch i386 i386/libavcodec.a -output libavcodec.a
lipo -create -arch armv6 armv6/libavutil.a -arch armv7 armv7/libavutil.a -arch i386 i386/libavutil.a -output libavutil.a
添加 libavcodec.a, libavutil.a, libavcodec/avcodec.h, 以及 libavutil 下所有头文件到工程中 (请注意路径).
解码的方法 (代码片断如下, 完整代码请参考相关附件):
1 struct AVCodec *fCodec = NULL; // Codec
2 struct AVCodecContext *fCodecContext = NULL; // Codec Context
3 struct AVFrame *fVideoFrame = NULL; // Frame
4
5 int fDisplayWidth = 0;
6 int fDisplayHeight = 0;
7
8
9
10 int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture,
11 int *got_picture_ptr,
12 const uint8_t *buf, int buf_size)
13 {
14 AVPacket avpkt;
15 av_init_packet(&avpkt);
16 avpkt.data = buf;
17 avpkt.size = buf_size;
18 // HACK for CorePNG to decode as normal PNG by default
19 avpkt.flags = AV_PKT_FLAG_KEY;
20 return avcodec_decode_video2(avctx, picture, got_picture_ptr, &avpkt);
21 }
22
23
24
25 int avc_decode_init(int width, int height)
26 {
27 if (fCodecContext != NULL) {
28 return 0;
29 }
30 avcodec_init();
31 avcodec_register_all();
32 fCodec = avcodec_find_decoder(CODEC_ID_H264);
33
34 fDisplayWidth = width;
35 fDisplayHeight = height;
36
37 CreateYUVTable();
38
39 fCodecContext = avcodec_alloc_context();
40 avcodec_open(fCodecContext, fCodec);
41 fVideoFrame = avcodec_alloc_frame();
42
43 return 1;
44 }
45
46
47
48 int avc_decode_release()
49 {
50 if (fCodecContext) {
51 avcodec_close(fCodecContext);
52 free(fCodecContext->priv_data);
53 free(fCodecContext);
54 fCodecContext = NULL;
55 }
56
57 if (fVideoFrame) {
58 free(fVideoFrame);
59 fVideoFrame = NULL;
60 }
61
62 DeleteYUVTable();
63 return 1;
64 }
65
66
67
68 int avc_decode(char* buf, int nalLen, char* out)
69 {
70 byte_t* data = (byte_t*)buf;
71 int frameSize = 0;
72
73 int ret = avcodec_decode_video(fCodecContext, fVideoFrame, &frameSize, data, nalLen);
74 if (ret <= 0) {
75 return ret;
76 }
77
78 int width = fCodecContext->width;
79 int height = fCodecContext->height;
80 DisplayYUV_32((uint32_t*)out, width, height, fDisplayWidth);
81 return ret;
82 }
2 struct AVCodecContext *fCodecContext = NULL; // Codec Context
3 struct AVFrame *fVideoFrame = NULL; // Frame
4
5 int fDisplayWidth = 0;
6 int fDisplayHeight = 0;
7
8
9
10 int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture,
11 int *got_picture_ptr,
12 const uint8_t *buf, int buf_size)
13 {
14 AVPacket avpkt;
15 av_init_packet(&avpkt);
16 avpkt.data = buf;
17 avpkt.size = buf_size;
18 // HACK for CorePNG to decode as normal PNG by default
19 avpkt.flags = AV_PKT_FLAG_KEY;
20 return avcodec_decode_video2(avctx, picture, got_picture_ptr, &avpkt);
21 }
22
23
24
25 int avc_decode_init(int width, int height)
26 {
27 if (fCodecContext != NULL) {
28 return 0;
29 }
30 avcodec_init();
31 avcodec_register_all();
32 fCodec = avcodec_find_decoder(CODEC_ID_H264);
33
34 fDisplayWidth = width;
35 fDisplayHeight = height;
36
37 CreateYUVTable();
38
39 fCodecContext = avcodec_alloc_context();
40 avcodec_open(fCodecContext, fCodec);
41 fVideoFrame = avcodec_alloc_frame();
42
43 return 1;
44 }
45
46
47
48 int avc_decode_release()
49 {
50 if (fCodecContext) {
51 avcodec_close(fCodecContext);
52 free(fCodecContext->priv_data);
53 free(fCodecContext);
54 fCodecContext = NULL;
55 }
56
57 if (fVideoFrame) {
58 free(fVideoFrame);
59 fVideoFrame = NULL;
60 }
61
62 DeleteYUVTable();
63 return 1;
64 }
65
66
67
68 int avc_decode(char* buf, int nalLen, char* out)
69 {
70 byte_t* data = (byte_t*)buf;
71 int frameSize = 0;
72
73 int ret = avcodec_decode_video(fCodecContext, fVideoFrame, &frameSize, data, nalLen);
74 if (ret <= 0) {
75 return ret;
76 }
77
78 int width = fCodecContext->width;
79 int height = fCodecContext->height;
80 DisplayYUV_32((uint32_t*)out, width, height, fDisplayWidth);
81 return ret;
82 }