~ubuntu-branches/ubuntu/trusty/linphone/trusty

« back to all changes in this revision

Viewing changes to mediastreamer2/src/videofilters/h264dec.c

  • Committer: Package Import Robot
  • Author(s): Luk Claes
  • Date: 2013-09-11 19:08:43 UTC
  • mfrom: (1.1.19) (16.1.12 sid)
  • Revision ID: package-import@ubuntu.com-20130911190843-fkydjxsdvy1fmx24
Tags: 3.6.1-2.1
* Non-maintainer upload.
* Apply Sebastian Ramacher's patch to fix FTBFS (Closes: #720668).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
mediastreamer2 library - modular sound and video processing and streaming
 
3
Copyright (C) 2010  Belledonne Communications SARL 
 
4
Author: Simon Morlat <simon.morlat@linphone.org>
 
5
 
 
6
This program is free software; you can redistribute it and/or
 
7
modify it under the terms of the GNU General Public License
 
8
as published by the Free Software Foundation; either version 2
 
9
of the License, or (at your option) any later version.
 
10
 
 
11
This program is distributed in the hope that it will be useful,
 
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with this program; if not, write to the Free Software
 
18
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
19
*/
 
20
 
 
21
#include "mediastreamer2/msfilter.h"
 
22
#include "mediastreamer2/rfc3984.h"
 
23
#include "mediastreamer2/msvideo.h"
 
24
#include "mediastreamer2/msticker.h"
 
25
 
 
26
#include "ffmpeg-priv.h"
 
27
 
 
28
#include "ortp/b64.h"
 
29
 
 
30
 
 
31
typedef struct _DecData{
 
32
        mblk_t *yuv_msg;
 
33
        mblk_t *sps,*pps;
 
34
        Rfc3984Context unpacker;
 
35
        MSPicture outbuf;
 
36
        struct SwsContext *sws_ctx;
 
37
        AVCodecContext av_context;
 
38
        unsigned int packet_num;
 
39
        uint8_t *bitstream;
 
40
        int bitstream_size;
 
41
        uint64_t last_error_reported_time;
 
42
        bool_t first_image_decoded;
 
43
}DecData;
 
44
 
 
45
static void ffmpeg_init(){
 
46
        static bool_t done=FALSE;
 
47
        if (!done){
 
48
#ifdef FF_API_AVCODEC_INIT
 
49
                avcodec_init();
 
50
#endif
 
51
                avcodec_register_all();
 
52
                done=TRUE;
 
53
        }
 
54
}
 
55
 
 
56
static void dec_open(DecData *d){
 
57
        AVCodec *codec;
 
58
        int error;
 
59
        codec=avcodec_find_decoder(CODEC_ID_H264);
 
60
        if (codec==NULL) ms_fatal("Could not find H264 decoder in ffmpeg.");
 
61
        avcodec_get_context_defaults(&d->av_context);
 
62
        error=avcodec_open(&d->av_context,codec);
 
63
        if (error!=0){
 
64
                ms_fatal("avcodec_open() failed.");
 
65
        }
 
66
}
 
67
 
 
68
static void dec_init(MSFilter *f){
 
69
        DecData *d=(DecData*)ms_new(DecData,1);
 
70
        ffmpeg_init();
 
71
        d->yuv_msg=NULL;
 
72
        d->sps=NULL;
 
73
        d->pps=NULL;
 
74
        d->sws_ctx=NULL;
 
75
        rfc3984_init(&d->unpacker);
 
76
        d->packet_num=0;
 
77
        dec_open(d);
 
78
        d->outbuf.w=0;
 
79
        d->outbuf.h=0;
 
80
        d->bitstream_size=65536;
 
81
        d->bitstream=ms_malloc0(d->bitstream_size);
 
82
        d->last_error_reported_time=0;
 
83
        f->data=d;
 
84
}
 
85
 
 
86
static void dec_preprocess(MSFilter* f) {
 
87
        DecData *s=(DecData*)f->data;
 
88
        s->first_image_decoded = FALSE;
 
89
}
 
90
 
 
91
static void dec_reinit(DecData *d){
 
92
        avcodec_close(&d->av_context);
 
93
        dec_open(d);
 
94
}
 
95
 
 
96
static void dec_uninit(MSFilter *f){
 
97
        DecData *d=(DecData*)f->data;
 
98
        rfc3984_uninit(&d->unpacker);
 
99
        avcodec_close(&d->av_context);
 
100
        if (d->yuv_msg) freemsg(d->yuv_msg);
 
101
        if (d->sps) freemsg(d->sps);
 
102
        if (d->pps) freemsg(d->pps);
 
103
        ms_free(d->bitstream);
 
104
        ms_free(d);
 
105
}
 
106
 
 
107
static mblk_t *get_as_yuvmsg(MSFilter *f, DecData *s, AVFrame *orig){
 
108
        AVCodecContext *ctx=&s->av_context;
 
109
 
 
110
        if (s->outbuf.w!=ctx->width || s->outbuf.h!=ctx->height){
 
111
                if (s->sws_ctx!=NULL){
 
112
                        sws_freeContext(s->sws_ctx);
 
113
                        s->sws_ctx=NULL;
 
114
                        freemsg(s->yuv_msg);
 
115
                        s->yuv_msg=NULL;
 
116
                }
 
117
                ms_message("Getting yuv picture of %ix%i",ctx->width,ctx->height);
 
118
                s->yuv_msg=ms_yuv_buf_alloc(&s->outbuf,ctx->width,ctx->height);
 
119
                s->outbuf.w=ctx->width;
 
120
                s->outbuf.h=ctx->height;
 
121
                s->sws_ctx=sws_getContext(ctx->width,ctx->height,ctx->pix_fmt,
 
122
                        ctx->width,ctx->height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR,
 
123
                        NULL, NULL, NULL);
 
124
        }
 
125
#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0,9,0)     
 
126
        if (sws_scale(s->sws_ctx,(const uint8_t * const *)orig->data,orig->linesize, 0,
 
127
                                        ctx->height, s->outbuf.planes, s->outbuf.strides)<0){
 
128
#else
 
129
        if (sws_scale(s->sws_ctx,(uint8_t **)orig->data,orig->linesize, 0,
 
130
                                        ctx->height, s->outbuf.planes, s->outbuf.strides)<0){
 
131
#endif
 
132
                ms_error("%s: error in sws_scale().",f->desc->name);
 
133
        }
 
134
        return dupmsg(s->yuv_msg);
 
135
}
 
136
 
 
137
static void update_sps(DecData *d, mblk_t *sps){
 
138
        if (d->sps)
 
139
                freemsg(d->sps);
 
140
        d->sps=dupb(sps);
 
141
}
 
142
 
 
143
static void update_pps(DecData *d, mblk_t *pps){
 
144
        if (d->pps)
 
145
                freemsg(d->pps);
 
146
        if (pps) d->pps=dupb(pps);
 
147
        else d->pps=NULL;
 
148
}
 
149
 
 
150
 
 
151
static bool_t check_sps_change(DecData *d, mblk_t *sps){
 
152
        bool_t ret=FALSE;
 
153
        if (d->sps){
 
154
                ret=(msgdsize(sps)!=msgdsize(d->sps)) || (memcmp(d->sps->b_rptr,sps->b_rptr,msgdsize(sps))!=0);
 
155
                if (ret) {
 
156
                        ms_message("SPS changed ! %i,%i",msgdsize(sps),msgdsize(d->sps));
 
157
                        update_sps(d,sps);
 
158
                        update_pps(d,NULL);
 
159
                }
 
160
        } else {
 
161
                ms_message("Receiving first SPS");
 
162
                update_sps(d,sps);
 
163
        }
 
164
        return ret;
 
165
}
 
166
 
 
167
static bool_t check_pps_change(DecData *d, mblk_t *pps){
 
168
        bool_t ret=FALSE;
 
169
        if (d->pps){
 
170
                ret=(msgdsize(pps)!=msgdsize(d->pps)) || (memcmp(d->pps->b_rptr,pps->b_rptr,msgdsize(pps))!=0);
 
171
                if (ret) {
 
172
                        ms_message("PPS changed ! %i,%i",msgdsize(pps),msgdsize(d->pps));
 
173
                        update_pps(d,pps);
 
174
                }
 
175
        }else {
 
176
                ms_message("Receiving first PPS");
 
177
                update_pps(d,pps);
 
178
        }
 
179
        return ret;
 
180
}
 
181
 
 
182
 
 
183
static void enlarge_bitstream(DecData *d, int new_size){
 
184
        d->bitstream_size=new_size;
 
185
        d->bitstream=ms_realloc(d->bitstream,d->bitstream_size);
 
186
}
 
187
 
 
188
static int nalusToFrame(DecData *d, MSQueue *naluq, bool_t *new_sps_pps){
 
189
        mblk_t *im;
 
190
        uint8_t *dst=d->bitstream,*src,*end;
 
191
        int nal_len;
 
192
        bool_t start_picture=TRUE;
 
193
        uint8_t nalu_type;
 
194
        *new_sps_pps=FALSE;
 
195
        end=d->bitstream+d->bitstream_size;
 
196
        while((im=ms_queue_get(naluq))!=NULL){
 
197
                src=im->b_rptr;
 
198
                nal_len=im->b_wptr-src;
 
199
                if (dst+nal_len+100>end){
 
200
                        int pos=dst-d->bitstream;
 
201
                        enlarge_bitstream(d, d->bitstream_size+nal_len+100);
 
202
                        dst=d->bitstream+pos;
 
203
                        end=d->bitstream+d->bitstream_size;
 
204
                }
 
205
                if (src[0]==0 && src[1]==0 && src[2]==0 && src[3]==1){
 
206
                        int size=im->b_wptr-src;
 
207
                        /*workaround for stupid RTP H264 sender that includes nal markers */
 
208
                        memcpy(dst,src,size);
 
209
                        dst+=size;
 
210
                }else{
 
211
                        nalu_type=(*src) & ((1<<5)-1);
 
212
                        if (nalu_type==7)
 
213
                                *new_sps_pps=check_sps_change(d,im) || *new_sps_pps;
 
214
                        if (nalu_type==8)
 
215
                                *new_sps_pps=check_pps_change(d,im) || *new_sps_pps;
 
216
                        if (start_picture || nalu_type==7/*SPS*/ || nalu_type==8/*PPS*/ ){
 
217
                                *dst++=0;
 
218
                                start_picture=FALSE;
 
219
                        }
 
220
                
 
221
                        /*prepend nal marker*/
 
222
                        *dst++=0;
 
223
                        *dst++=0;
 
224
                        *dst++=1;
 
225
                        *dst++=*src++;
 
226
                        while(src<(im->b_wptr-3)){
 
227
                                if (src[0]==0 && src[1]==0 && src[2]<3){
 
228
                                        *dst++=0;
 
229
                                        *dst++=0;
 
230
                                        *dst++=3;
 
231
                                        src+=2;
 
232
                                }
 
233
                                *dst++=*src++;
 
234
                        }
 
235
                        *dst++=*src++;
 
236
                        *dst++=*src++;
 
237
                        *dst++=*src++;
 
238
                }
 
239
                freemsg(im);
 
240
        }
 
241
        return dst-d->bitstream;
 
242
}
 
243
 
 
244
static void dec_process(MSFilter *f){
 
245
        DecData *d=(DecData*)f->data;
 
246
        mblk_t *im;
 
247
        MSQueue nalus;
 
248
        AVFrame orig;
 
249
        ms_queue_init(&nalus);
 
250
        while((im=ms_queue_get(f->inputs[0]))!=NULL){
 
251
                /*push the sps/pps given in sprop-parameter-sets if any*/
 
252
                if (d->packet_num==0 && d->sps && d->pps){
 
253
                        mblk_set_timestamp_info(d->sps,mblk_get_timestamp_info(im));
 
254
                        mblk_set_timestamp_info(d->pps,mblk_get_timestamp_info(im));
 
255
                        rfc3984_unpack(&d->unpacker,d->sps,&nalus);
 
256
                        rfc3984_unpack(&d->unpacker,d->pps,&nalus);
 
257
                        d->sps=NULL;
 
258
                        d->pps=NULL;
 
259
                }
 
260
                rfc3984_unpack(&d->unpacker,im,&nalus);
 
261
                if (!ms_queue_empty(&nalus)){
 
262
                        int size;
 
263
                        uint8_t *p,*end;
 
264
                        bool_t need_reinit=FALSE;
 
265
 
 
266
                        size=nalusToFrame(d,&nalus,&need_reinit);
 
267
                        if (need_reinit)
 
268
                                dec_reinit(d);
 
269
                        p=d->bitstream;
 
270
                        end=d->bitstream+size;
 
271
                        while (end-p>0) {
 
272
                                int len;
 
273
                                int got_picture=0;
 
274
                                AVPacket pkt;
 
275
                                avcodec_get_frame_defaults(&orig);
 
276
                                av_init_packet(&pkt);
 
277
                                pkt.data = p;
 
278
                                pkt.size = end-p;
 
279
                                len=avcodec_decode_video2(&d->av_context,&orig,&got_picture,&pkt);
 
280
                                if (len<=0) {
 
281
                                        ms_warning("ms_AVdecoder_process: error %i.",len);
 
282
                                        if ((f->ticker->time - d->last_error_reported_time)>5000 || d->last_error_reported_time==0) {
 
283
                                                d->last_error_reported_time=f->ticker->time;
 
284
                                                ms_filter_notify_no_arg(f,MS_VIDEO_DECODER_DECODING_ERRORS);
 
285
                                        }
 
286
                                        break;
 
287
                                }
 
288
                                if (got_picture) {
 
289
                                        ms_queue_put(f->outputs[0],get_as_yuvmsg(f,d,&orig));
 
290
                                        if (!d->first_image_decoded) {
 
291
                                                ms_filter_notify_no_arg(f,MS_VIDEO_DECODER_FIRST_IMAGE_DECODED);
 
292
                                                d->first_image_decoded = TRUE;
 
293
                                        }
 
294
                                }
 
295
                                p+=len;
 
296
                        }
 
297
                }
 
298
                d->packet_num++;
 
299
        }
 
300
}
 
301
 
 
302
static int dec_add_fmtp(MSFilter *f, void *arg){
 
303
        DecData *d=(DecData*)f->data;
 
304
        const char *fmtp=(const char *)arg;
 
305
        char value[256];
 
306
        if (fmtp_get_value(fmtp,"sprop-parameter-sets",value,sizeof(value))){
 
307
                char * b64_sps=value;
 
308
                char * b64_pps=strchr(value,',');
 
309
                if (b64_pps){
 
310
                        *b64_pps='\0';
 
311
                        ++b64_pps;
 
312
                        ms_message("Got sprop-parameter-sets : sps=%s , pps=%s",b64_sps,b64_pps);
 
313
                        d->sps=allocb(sizeof(value),0);
 
314
                        d->sps->b_wptr+=b64_decode(b64_sps,strlen(b64_sps),d->sps->b_wptr,sizeof(value));
 
315
                        d->pps=allocb(sizeof(value),0);
 
316
                        d->pps->b_wptr+=b64_decode(b64_pps,strlen(b64_pps),d->pps->b_wptr,sizeof(value));
 
317
                }
 
318
        }
 
319
        return 0;
 
320
}
 
321
 
 
322
static int reset_first_image(MSFilter* f, void *data) {
 
323
        DecData *d=(DecData*)f->data;
 
324
        d->first_image_decoded = FALSE;
 
325
        return 0;
 
326
}
 
327
 
 
328
static MSFilterMethod  h264_dec_methods[]={
 
329
        {       MS_FILTER_ADD_FMTP      ,       dec_add_fmtp    },
 
330
        {   MS_VIDEO_DECODER_RESET_FIRST_IMAGE_NOTIFICATION, reset_first_image },
 
331
        {       0                       ,       NULL    }
 
332
};
 
333
 
 
334
#ifndef _MSC_VER
 
335
 
 
336
MSFilterDesc ms_h264_dec_desc={
 
337
        .id=MS_H264_DEC_ID,
 
338
        .name="MSH264Dec",
 
339
        .text="A H264 decoder based on ffmpeg project.",
 
340
        .category=MS_FILTER_DECODER,
 
341
        .enc_fmt="H264",
 
342
        .ninputs=1,
 
343
        .noutputs=1,
 
344
        .init=dec_init,
 
345
        .preprocess=dec_preprocess,
 
346
        .process=dec_process,
 
347
        .uninit=dec_uninit,
 
348
        .methods=h264_dec_methods
 
349
};
 
350
 
 
351
#else
 
352
 
 
353
 
 
354
MSFilterDesc ms_h264_dec_desc={
 
355
        MS_H264_DEC_ID,
 
356
        "MSH264Dec",
 
357
        "A H264 decoder based on ffmpeg project.",
 
358
        MS_FILTER_DECODER,
 
359
        "H264",
 
360
        1,
 
361
        1,
 
362
        dec_init,
 
363
        dec_preprocess,
 
364
        dec_process,
 
365
        NULL,
 
366
        dec_uninit,
 
367
        h264_dec_methods
 
368
};
 
369
 
 
370
#endif
 
371
 
 
372
MS_FILTER_DESC_EXPORT(ms_h264_dec_desc)
 
373