socketref,再见!高德

https://github.com/adoggie

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  246 Posts :: 4 Stories :: 312 Comments :: 0 Trackbacks

常用链接

留言簿(54)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

项目需求开发网络流媒体播放器,整个项目就一人开发,整个系统平台,包括调度,存储集群服务,影像同步导入、系统api接口、视频查询和播放客户端,一切有了python就变得简单。一个人在战斗,还是蛮有劲道。

pyqt开发播放界面,python用于网络通信和粘合逻辑,ffmpeg用于解码,google一圈试用了几个pyffmpeg的库,非常不理想,干脆自己做:

采用ctypes访问dll,测试解码并将视频帧转换RGB24写入PPM文件,imagemagick转换为jpg,okay。。

C动态库
结构定义: 
 1 #define FF_BOOL int
 2 #define FF_TRUE 1
 3 #define FF_FALSE 0
 4 
 5 typedef unsigned char  StreamByte_t;
 6 
 7 //视频流信息
 8 struct MediaStreamInfo_t{
 9     int codec_type;
10     int codec_id;
11     int width;
12     int height;
13     int gopsize;
14     int pixfmt;
15     int tb_num;
16     int tb_den;
17     int bitrate;
18     int frame_number;
19     int videostream; //视频流编号
20 };
21 
22 struct MediaVideoFrame_t{
23     StreamByte_t *    rgb24;
24     size_t            size;
25     int                width;
26     int                height;
27     unsigned int    sequence; //控制播放顺序
28     unsigned int    duration; //播放时间
29 };
30 
31 struct MediaPacket_t{
32      StreamByte_t*    data;
33      size_t            size;
34     AVPacket    *    pkt;
35     int                stream;    //流编号 
36     int                dts;
37     int                pts;
38     size_t            sequence;
39     size_t            duration;
40 
41 };
42 
43 struct MediaFormatContext_t;
44 
45 //解码器
46 struct MediaCodecContext_t{
47     AVCodecContext * codecCtx;    //AVCodecContext*
48     AVCodec *        codec;    
49     int                stream; //流编号
50     AVFrame *        rgbframe24; //
51     AVFrame*        frame;    //
52     StreamByte_t*    buffer;
53     size_t            bufsize;
54     void *            user;
55     MediaStreamInfo_t si;
56 };
57 
58 struct MediaFormatContext_t{
59     AVFormatContext * fc; //AVFormatContext* 
60     MediaStreamInfo_t video;    //视频信息
61     
62 };

实现部分
  1 
  2 MEDIACODEC_API   FF_BOOL InitLib(){
  3     avcodec_init();
  4     av_register_all();
  5     return FF_TRUE;
  6 }
  7 
  8 MEDIACODEC_API void Cleanup(){
  9 
 10 }
 11 
 12 MEDIACODEC_API  MediaCodecContext_t* InitAvCodec(MediaStreamInfo_t* si){
 13     MediaCodecContext_t* ctx;
 14     AVCodecContext * codecCtx;
 15     
 16 
 17     codecCtx = avcodec_alloc_context();
 18     codecCtx->width = si->width;
 19     codecCtx->height = si->height;
 20     codecCtx->time_base.num = si->tb_num;
 21     codecCtx->time_base.den = si->tb_den;
 22     codecCtx->bit_rate = si->bitrate;
 23     codecCtx->frame_number = si->frame_number;
 24     codecCtx->codec_type =(AVMediaType) si->codec_type;
 25     codecCtx->codec_id = (CodecID)si->codec_id;
 26 
 27     AVCodec *codec;
 28     codec = avcodec_find_decoder(codecCtx->codec_id);
 29     if(codec == NULL){
 30         //avcodec_free_context()
 31         return NULL;
 32     }
 33     if(avcodec_open(codecCtx, codec)<0){
 34         return NULL;
 35     }
 36 
 37     ctx = new MediaCodecContext_t();
 38     ctx->codecCtx    = codecCtx;
 39     ctx->codec        = codec;
 40     ctx->stream        = si->videostream;
 41     ctx->si = *si;
 42 
 43     uint8_t *buffer;
 44     size_t numBytes;
 45     ctx->rgbframe24 = avcodec_alloc_frame();
 46     ctx->frame =  avcodec_alloc_frame();
 47 
 48     numBytes=avpicture_get_size(PIX_FMT_RGB24, codecCtx->width,codecCtx->height);
 49     buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
 50     ctx->buffer = (StreamByte_t*)buffer;
 51     ctx->bufsize = numBytes;
 52 
 53     avpicture_fill((AVPicture *)ctx->rgbframe24, buffer, PIX_FMT_RGB24,codecCtx->width, codecCtx->height); // bind buffer with frame
 54 
 55     return ctx;
 56 }
 57 
 58 
 59 MEDIACODEC_API void FreeAvCodec(MediaCodecContext_t* ctx){
 60     AVCodecContext * codecCtx;
 61     AVCodec *codec;
 62     codecCtx = (AVCodecContext*) ctx->codecCtx;
 63     codec = (AVCodec*) ctx->codec;
 64     avcodec_close(codecCtx);
 65     
 66     av_free(ctx->buffer);
 67     av_free(ctx->rgbframe24);
 68     av_free(ctx->frame);
 69     delete ctx;
 70 }
 71 
 72 
 73 //图像格式转换
 74 int convert_picture(AVFrame *rgbframe, AVFrame *frame, int width, int height, PixelFormat format,PixelFormat toformat){
 75     struct SwsContext *sws;
 76 
 77     if (format == PIX_FMT_YUV420P){        
 78         sws = sws_getContext(width, height, format, width, height, toformat, SWS_FAST_BILINEAR, NULL, NULL, NULL);
 79         if (sws == 0){
 80             return -1;
 81         }
 82         if (sws_scale(sws, frame->data, frame->linesize, 0, height, rgbframe->data, rgbframe->linesize)){
 83             //return -1;
 84         }
 85     }else{
 86         return -1;
 87     }
 88     return 0;
 89 }
 90 
 91 MEDIACODEC_API MediaVideoFrame_t * DecodeVideoFrame(MediaCodecContext_t* ctx,MediaPacket_t* pkt){
 92     MediaVideoFrame_t * frame;
 93     
 94     if(pkt->stream != ctx->stream){
 95         return NULL;
 96     }
 97     int frameFinished;
 98     
 99     AVCodecContext* codecCtx;
100     codecCtx = (AVCodecContext*)ctx->codecCtx;
101 
102     avcodec_decode_video(codecCtx, ctx->frame, &frameFinished,pkt->data, pkt->size);
103     if( !frameFinished ){
104         return NULL;
105     }
106     int r;
107     r = convert_picture(ctx->rgbframe24,ctx->frame,codecCtx->width,codecCtx->height,codecCtx->pix_fmt,PIX_FMT_RGB24);
108     if(r){
109         return NULL;
110     }
111     // 复制一份
112     frame = new MediaVideoFrame_t();
113     frame->rgb24 = (StreamByte_t*)malloc(ctx->bufsize);
114     frame->size =ctx->bufsize;
115     memcpy(frame->rgb24,ctx->buffer,ctx->bufsize);
116     frame->width = ctx->frame->width;
117     frame->height = ctx->frame->height;
118     frame->sequence = pkt->sequence;
119     frame->duration = pkt->duration;
120 
121     return frame;
122 }
123 
124 MEDIACODEC_API void FreeVideoFrame(MediaVideoFrame_t* frame){
125     if(frame->rgb24){
126         free(frame->rgb24);
127     }
128     delete frame;
129 }
130 
131 MEDIACODEC_API MediaPacket_t * AllocPacket(){
132     MediaPacket_t *pkt;
133 
134     pkt = new MediaPacket_t();
135     pkt->pkt =new AVPacket();
136     pkt->size = 0;
137     pkt->data = NULL;
138     pkt->stream = -1;
139     return pkt;
140 }
141 
142 // s - 0 : 不释放内部的 av_free_packet(); 1 - 释放packet内部数据
143 MEDIACODEC_API void FreePacket(MediaPacket_t* pkt,int s){
144     AVPacket* packet;
145     packet = pkt->pkt;
146     if(s){
147         av_free_packet(packet);
148     }
149     delete packet;
150     delete pkt;
151 }
152 
153 
154 MEDIACODEC_API MediaFormatContext_t* InitAvFormatContext(char * file){
155     MediaFormatContext_t* ctx;
156     AVFormatContext *ic;
157     int videoStream=-1;
158     unsigned int i;
159     AVCodecContext *codecCtx;
160 
161 
162     
163     
164     ic = avformat_alloc_context();
165     if(avformat_open_input(&ic, file, NULL,NULL)!=0){
166         avformat_free_context(ic);
167         return NULL; 
168     }
169     
170     if(av_find_stream_info(ic)<0){//查询文件流信息
171         avformat_free_context(ic);
172         return NULL;
173     }
174     
175     
176     for(i=0; i < ic->nb_streams; i++){
177         if(ic->streams[i]->codec->codec_type== CODEC_TYPE_VIDEO) {
178             videoStream=i;
179             break;
180         }
181     }
182     if( videoStream ==-1){
183         avformat_free_context(ic);
184         return NULL;
185     }
186     codecCtx = ic->streams[videoStream]->codec;
187 
188     ctx = new MediaFormatContext_t();
189     ctx->fc = ic;
190     ctx->video.codec_type = (int)CODEC_TYPE_VIDEO;
191     ctx->video.codec_id = (int)codecCtx->codec_id;
192     ctx->video.bitrate = codecCtx->bit_rate;
193     ctx->video.frame_number = codecCtx->frame_number;
194     ctx->video.gopsize = codecCtx->gop_size;
195     ctx->video.height = codecCtx->height;
196     ctx->video.pixfmt = codecCtx->pix_fmt;
197     ctx->video.tb_den = codecCtx->time_base.den;
198     ctx->video.tb_num = codecCtx->time_base.num;
199     ctx->video.width = codecCtx->width;
200     ctx->video.videostream = videoStream;
201     return ctx;
202 }
203 
204 MEDIACODEC_API void FreeAvFormatContext(MediaFormatContext_t* ctx){
205     if(ctx->fc){
206         avformat_free_context((AVFormatContext*)ctx->fc);
207     }
208     delete ctx;
209 }
210 
211 MEDIACODEC_API MediaPacket_t* ReadNextPacket(MediaFormatContext_t* ctx){
212     MediaPacket_t* pkt = NULL;
213     
214     while(1){
215         pkt = AllocPacket();
216         if( pkt == NULL){
217             return NULL;
218         }
219         if( av_read_frame((AVFormatContext*)ctx->fc, (AVPacket*)pkt->pkt) <0 ){
220             FreePacket(pkt,0); //并没有释放内部的packet数据
221             //printf("read_fream error!\n");
222             return NULL;
223         }
224         if( ctx->video.videostream == pkt->pkt->stream_index){
225             pkt->data = pkt->pkt->data;
226             pkt->size = pkt->pkt->size;
227             pkt->stream = pkt->pkt->stream_index;
228             pkt->duration = pkt->pkt->duration;
229             return pkt;    
230         }        
231         FreePacket(pkt,1);
232     }
233 
234     return NULL;
235 }
236 
237 MEDIACODEC_API void FlushBuffer(MediaCodecContext_t* codec){
238     avcodec_flush_buffers(codec->codecCtx);
239 }
240 
241 
242 //跳转到指定时间 
243 MEDIACODEC_API int SeekToTime(MediaFormatContext_t* ctx,int timesec){
244 //avcodec_flush_buffers(pFormatCtx->streams[video_stream]->codec);
245     
246     if( av_seek_frame(ctx->fc,-1,timesec*AV_TIME_BASE,AVSEEK_FLAG_BACKWARD)<0){
247         return -1;
248     }
249     //avcodec_flush_buffers(ctx->streams[video_stream]->codec);
250     return 0;
251 }
252 
253 MEDIACODEC_API void ReadReset(MediaFormatContext_t* ctx){
254     SeekToTime(ctx,0);
255 }
256 

python测试代码: 

 1 
 2 import ffmpeg
 3 
 4 
 5 def printStreamInfo(s):
 6     print s.codec_type,'codec_id:',s.codec_id,\
 7         'width:',s.width,'height:',s.height,\
 8         'gopsize:',s.gopsize,'pixfmt:',s.pixfmt,\
 9         'timebase_num:',s.tb_num,'timebase_den:',s.tb_den,\
10         'bitrate:',s.bitrate,'framenumber:',s.frame_number,\
11         'streamindex:',s.videostream
12 
13 def printFrameInfo(f):
14     print len(f.rgb24[:f.size]),'width:',f.width,'height:',f.height,'duration:',f.duration,'size:',f.size
15     
16 
17 def saveppm(f,file):
18     fp = open(file,'wb')
19     if not fp:
20         return
21     fp.write( "P6\n%d %d\n255\n"%(f.width,f.height) )
22     fp.write(f.rgb24[:f.size])
23     fp.close()
24     print file
25         
26     
27 ffmpeg.InitLib()
28 fc =  ffmpeg.InitAvFormatContext('d:/movies/marieMcCray.avi')
29 printStreamInfo(fc.contents.video)
30 bytes=0
31 codec = ffmpeg.InitAvCodec(fc.contents.video)
32 print codec #apply a codec
33 
34 cnt=0
35 while True:
36     pkt = ffmpeg.ReadNextPacket(fc)
37     if not pkt:break
38     bytes += pkt.contents.size
39     frame = ffmpeg.DecodeVideoFrame(codec,pkt)
40     if frame:
41         cnt+=1
42         printFrameInfo(frame.contents)
43         if cnt < 100:
44             saveppm(frame.contents,"d:/temp4/%s_xx.ppm"%cnt)
45             os.system('convertx %s %s'%("d:/temp4/%s_xx.ppm"%cnt,"d:/temp4/%s_xx.jpg"%cnt))
46         ffmpeg.FreeVideoFrame(frame) #memory leak
47     print pkt.contents.stream,pkt.contents.size,pkt.contents.duration
48     ffmpeg.FreePacket(pkt,1)
49 







posted on 2012-03-15 02:01 放屁阿狗 阅读(1538) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理