py-ffmpeg在python中利用ctype包装ffmpeg

py-ffmpeg在python中利用ctype包装ffmpeg
写代码,写好代码其实并不难,但如果要做好文档,能完整阐述清楚自己的构思、想法和逻辑结构,这比较难,自己也缺少这方面的耐心。
很多opensource的代码根本不需要文档也能一目了然,这是一种定力
多年前的项目中使用到python和ffmpeg, 网络上搜索了一下,均不能满足自己的要求。ffmpeg的python绑定提供的均是文件级的访问控制,也就是说没有暴露更多的可控接口来用。
所以还是一切都自己来做
ffmpeg采用0.81版本以上,当时发现mov文件在0.71以下无法正常解码,到0.81则解决了此问题。
python包装ffmpeg的方式很多,最好的可能就是swig,但太烦了,最后选择ctypes来访问ffmpeg接口。 
如果直接使用ffmpeg的api接口也不太合适,因为要暴露很多ffmpeg的接口、数据类型、常数定义等。
所以我是这么处理:   
  1. 编写一个功能动态库来包装ffmpeg,提供基本的业务功能 ,屏蔽ffmpeg细节,这里叫ffmpeg_media_codec.dll
  2. 用ctypes包装此ffmpeg_media_codec.dll,这里是ffmpeg.py
  3. 业务代码使用ffmpeg.py提供的接口访问、解码多媒体文件 
代码: http://sw2us.com/static/projects/py-ffmpeg/

ffmpeg_media_codec.dll 暴露的c接口 

 1 ffmpeg lib  interface list:
 2 ===========================
 4 typedef unsigned  char  StreamByte_t;
 6  struct MediaStreamInfo_t{
 7      int codec_type;
 8      int codec_id;
 9      int width;
10      int height;
11      int gopsize;
12      int pixfmt;
13      int tb_num;
14      int tb_den;
15      int bitrate;
16      int frame_number;
17      int videostream;  // 视频流编号
18  };
19 
20  struct MediaVideoFrame_t{
21     StreamByte_t *    rgb24;
22     size_t            size;
23      int                width;
24      int                height;
25     unsigned  int    sequence;  // 控制播放顺序
26      unsigned  int    duration;  // 播放时间
27  };
28 
29  struct MediaPacket_t{
30      StreamByte_t*    data;
31      size_t            size;
32     AVPacket    *    pkt;
33      int                stream;     // 流编号 
34       int                dts;
35      int                pts;
36     size_t            sequence;
37     size_t            duration;
39 };
40 
41  struct MediaFormatContext_t;
42 
43  // 解码器
44  struct MediaCodecContext_t{
45     AVCodecContext * codecCtx;     // AVCodecContext*
46      AVCodec *        codec;    
47      int                stream;  // 流编号
48      AVFrame *        rgbframe24;  //
49      AVFrame*        frame;     //
50      StreamByte_t*    buffer;
51     size_t            bufsize;
52      void *            user;
53     MediaStreamInfo_t si;
54 };
55 
56  struct MediaFormatContext_t{
57     AVFormatContext * fc;  // AVFormatContext* 
58      MediaStreamInfo_t video;     // 视频信息
60 };
66 #ifdef __cplusplus
67   extern "C" {  
68  #endif
69 
70  int InitLib();         //初始化解码库
71  void Cleanup();    //
73 MediaCodecContext_t* InitAvCodec(MediaStreamInfo_t* si);    //根据媒体类型分配解码器对象
74  void FreeAvCodec(MediaCodecContext_t* codec);                  //释放解码器对象
76 MediaVideoFrame_t * DecodeVideoFrame(MediaCodecContext_t* ctx,MediaPacket_t* pkt);  //送入媒体包进行解码,返回视频帧
77  void FreeVideoFrame(MediaVideoFrame_t* frame);                  //释放视频帧
79 MediaPacket_t * AllocPacket();                                             //分配一个流媒体包对象(用于网传)
80  void FreePacket(MediaPacket_t* pkt);                                    //释放流媒体包
82 MediaFormatContext_t* InitAvFormatContext( char * file);           // 媒体文件访问上下文,申请
83  void FreeAvFormatContext(MediaFormatContext_t* ctx);           // 释放
84  MediaPacket_t* ReadNextPacket(MediaFormatContext_t* ctx);   //读媒体文件一个数据包
85  void ReadReset(MediaFormatContext_t* ctx) ;                 // 重置媒体访问读取位置
86  int SeekToTime( int timesec) ;                                      // 跳跃到指定时间

ffmpeg.py 包装:

  1  import ctypes
  2  from ctypes  import *

  5 _lib = cdll.LoadLibrary( ' ffmpeg.dll ')
  6 
  7 _int_types = (c_int16, c_int32)
  8  if hasattr(ctypes,  ' c_int64 '):
  9      #  Some builds of ctypes apparently do not have c_int64
 10       #  defined; it's a pretty good bet that these builds do not
 11       #  have 64-bit pointers.
 12      _int_types += (ctypes.c_int64,)
 13  for t  in _int_types:
 14      if sizeof(t) == sizeof(c_size_t):
 15         c_ptrdiff_t = t
 16 
 17  class c_void(Structure):
 18      #  c_void_p is a buggy return type, converting to int, so
 19       #  POINTER(None) == c_void_p is actually written as
 20       #  POINTER(c_void), so it can be treated as a real pointer.
 21      _fields_ = [( ' dummy ', c_int)]

 26  class MediaStreamInfo_t(Structure):
 27     _fields_ = [
 28         ( ' codec_type ', c_int),
 29         ( ' codec_id ', c_int),
 30         ( ' width ', c_int),
 31         ( ' height ', c_int),
 32         ( ' gopsize ', c_int),
 33         ( ' pixfmt ', c_int),
 34         ( ' tb_num ',c_int),
 35         ( ' tb_den ',c_int),
 36         ( ' bitrate ',c_int),
 37         ( ' frame_number ',c_int),
 38         ( ' videostream ',c_int),
 39         ( ' duration ',c_int),
 40         ( ' extr ',POINTER(c_char)),  # 解码器 额外hash表数据
 41          ( ' extrsize ',c_int),
 42     ]
 43 
 44  class MediaVideoFrame_t(Structure):
 45     _fields_=[
 46         ( ' rgb24 ',POINTER(c_char)),
 47         ( ' size ',c_uint),
 48         ( ' width ',c_int),
 49         ( ' height ',c_int),
 50         ( ' sequence ',c_uint),
 51         ( ' duration ',c_uint)
 52     ]
 53     
 54  class MediaPacket_t(Structure):
 55     _fields_=[
 56         ( ' data ',POINTER(c_char)),
 57         ( ' size ',c_uint),
 58         ( ' pkt ',c_char_p),
 59         ( ' stream ',c_int),
 60         ( ' dts ',c_int),
 61         ( ' pts ',c_int),
 62         ( ' sequence ',c_uint),
 63         ( ' duration ',c_uint)
 64     ]
 65     
 66     
 67  class MediaCodecContext_t(Structure):
 68     _fields_=[
 69         ( ' codecCtx ',c_char_p),
 70         ( ' codec ',c_char_p),
 71         ( ' stream ',c_int),
 72         ( ' rgbframe24 ',c_char_p),
 73         ( ' frame ',c_char_p),
 74         ( ' buffer ',c_char_p),
 75         ( ' bufsize ',c_uint),
 76         ( ' user ',c_char_p),
 77         ( ' si ',MediaStreamInfo_t)
 78     ]    
 79     
 80  class MediaFormatContext_t(Structure):
 81     _fields_=[
 82         ( ' fc ',c_char_p),
 83         ( ' video ',MediaStreamInfo_t)
 84     ]
 85     
 86 InitAvCodec = _lib.InitAvCodec
 87 InitAvCodec.restype = POINTER(MediaCodecContext_t)
 88 InitAvCodec.argtypes = [POINTER(MediaStreamInfo_t)]
 89 
 90 
 91 FreeAvCodec = _lib.FreeAvCodec
 92 FreeAvCodec.restype = None
 93 FreeAvCodec.argtypes = [POINTER(MediaCodecContext_t)]
 96 DecodeVideoFrame = _lib.DecodeVideoFrame
 97 DecodeVideoFrame.restype = POINTER(MediaVideoFrame_t)
 98 DecodeVideoFrame.argtypes = [POINTER(MediaCodecContext_t),POINTER(MediaPacket_t)]
100 FreeVideoFrame = _lib.FreeVideoFrame
101 FreeVideoFrame.restype = None
102 FreeVideoFrame.argtypes = [POINTER(MediaVideoFrame_t)]  
104 AllocPacket = _lib.AllocPacket
105 AllocPacket.restype = POINTER(MediaPacket_t)
106 AllocPacket.argtypes = []
109 FreePacket = _lib.FreePacket
110 FreePacket.restype = None
111 FreePacket.argtypes = [POINTER(MediaPacket_t),c_int]
113 InitAvFormatContext = _lib.InitAvFormatContext
114 InitAvFormatContext.restype = POINTER(MediaFormatContext_t)
115 InitAvFormatContext.argtypes = [c_char_p]
117 FreeAvFormatContext = _lib.FreeAvFormatContext
118 FreeAvFormatContext.restype = None
119 FreeAvFormatContext.argtypes = [POINTER(MediaFormatContext_t)]
122 ReadNextPacket = _lib.ReadNextPacket
123 ReadNextPacket.restype = POINTER(MediaPacket_t)
124 ReadNextPacket.argtypes = [POINTER(MediaFormatContext_t)]
127 ReadReset = _lib.ReadReset
128 ReadReset.restype = None
129 ReadReset.argtypes = [POINTER(MediaFormatContext_t)]
130 
131 SeekToTime = _lib.SeekToTime
132 SeekToTime.restype = c_int
133 SeekToTime.argtypes = [POINTER(MediaFormatContext_t),c_int]
134 
135 FlushBuffer = _lib.FlushBuffer
136 FlushBuffer.restype =None
137 FlushBuffer.argtypes = [POINTER(MediaCodecContext_t)]
138 
139 InitLib = _lib.InitLib
140 InitLib.restype =None
141 InitLib.argtypes = []
142 
143 Cleanup = _lib.Cleanup
144 Cleanup.restype =None
145 Cleanup.argtypes = []

好了,看看如何使用这些接口 
视频文件播放:       http://sw2us.com/static/projects/py-ffmpeg/test_qt.py

你可能感兴趣的:(py-ffmpeg在python中利用ctype包装ffmpeg)