]> git.mxchange.org Git - flightgear.git/blob - 3rdparty/iaxclient/lib/codec_ffmpeg.c
VS2015 compatability fixes.
[flightgear.git] / 3rdparty / iaxclient / lib / codec_ffmpeg.c
1 /*
2  * iaxclient: a cross-platform IAX softphone library
3  *
4  * Copyrights:
5  * Copyright (C) 2003-2006, Horizon Wimba, Inc.
6  * Copyright (C) 2007, Wimba, Inc.
7  *
8  * Contributors:
9  * Steve Kann <stevek@stevek.com>
10  * Peter Grayson <jpgrayson@gmail.com>
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU Lesser (Library) General Public License.
14  *
15  * A video codec using the ffmpeg library.
16  * 
17  * TODO: this code still uses its own slicing mechanism
18  * It should be converted to use the API provided in slice.[ch]
19  */
20
21 #include <stdlib.h>
22
23 #include "codec_ffmpeg.h"
24 #include "iaxclient_lib.h"
25
26 #ifdef WIN32
27 #include "libavcodec/avcodec.h"
28 #else
29 #include <ffmpeg/avcodec.h>
30 #endif
31
32 struct slice_header_t
33 {
34         unsigned char version;
35         unsigned short source_id;
36         unsigned char frame_index;
37         unsigned char slice_index;
38         unsigned char num_slices;
39 };
40
41 struct encoder_ctx
42 {
43         AVCodecContext * avctx;
44         AVFrame * picture;
45
46         struct slice_header_t slice_header;
47
48         unsigned char *frame_buf;
49         int frame_buf_len;
50 };
51
52 struct decoder_ctx
53 {
54         AVCodecContext * avctx;
55         AVFrame * picture;
56
57         struct slice_header_t slice_header;
58         int frame_size;
59
60         unsigned char * frame_buf;
61         int frame_buf_len;
62 };
63
64 static struct slice_set_t * g_slice_set = 0;
65
66 static enum CodecID map_iaxc_codec_to_avcodec(int format)
67 {
68         switch (format)
69         {
70         case IAXC_FORMAT_H261:
71                 return CODEC_ID_H261;
72
73         case IAXC_FORMAT_H263:
74                 return CODEC_ID_H263;
75
76         case IAXC_FORMAT_H263_PLUS:
77                 return CODEC_ID_H263P;
78
79         case IAXC_FORMAT_MPEG4:
80                 return CODEC_ID_MPEG4;
81
82         case IAXC_FORMAT_H264:
83                 return CODEC_ID_H264;
84
85         case IAXC_FORMAT_THEORA:
86                 return CODEC_ID_THEORA;
87
88         default:
89                 return CODEC_ID_NONE;
90         }
91 }
92
93 static void destroy(struct iaxc_video_codec *c)
94 {
95         if (c)
96         {
97                 struct encoder_ctx *e = (struct encoder_ctx *) c->encstate;
98                 struct decoder_ctx *d = (struct decoder_ctx *) c->decstate;
99
100                 if (e)
101                 {
102                         av_freep(&e->avctx);
103                         av_freep(&e->picture);
104                         if (e->frame_buf)
105                                 free(e->frame_buf);
106                         free(e);
107                 }
108
109                 if (d)
110                 {
111                         av_freep(&d->avctx);
112                         av_freep(&d->picture);
113                         if (d->frame_buf)
114                                 free(d->frame_buf);
115                         free(d);
116                 }
117
118                 free(c);
119         }
120 }
121
122 static void reset_decoder_frame_state(struct decoder_ctx * d)
123 {
124         memset(d->frame_buf, 0, d->frame_buf_len);
125         d->frame_size = 0;
126         d->slice_header.slice_index = 0;
127 }
128
129 static int frame_to_frame_xlate(AVCodecContext * avctx, AVFrame * picture,
130                 int * outlen, char * out)
131 {
132         int line;
133
134         *outlen = avctx->width * avctx->height * 6 / 4;
135
136         for ( line = 0; line < avctx->height / 2; ++line )
137         {
138                 /* y even */
139                 memcpy(out + avctx->width * (2 * line + 0),
140                        picture->data[0] + (2 * line + 0) * picture->linesize[0],
141                        avctx->width);
142
143                 /* y odd */
144                 memcpy(out + avctx->width * (2 * line + 1),
145                        picture->data[0] + (2 * line + 1) * picture->linesize[0],
146                        avctx->width);
147
148                 /* u + v */
149                 memcpy(out + avctx->width * avctx->height
150                                 + line * avctx->width / 2,
151                        picture->data[1] + line * picture->linesize[1],
152                        avctx->width / 2);
153
154                 memcpy(out + avctx->width * avctx->height * 5 / 4
155                                 + line * avctx->width / 2,
156                        picture->data[2] + line * picture->linesize[2],
157                        avctx->width / 2);
158         }
159
160         return 0;
161 }
162
163 static int pass_frame_to_decoder(AVCodecContext * avctx, AVFrame * picture,
164                 int inlen, unsigned char * in, int * outlen, char * out)
165 {
166         int bytes_decoded;
167         int got_picture;
168
169         bytes_decoded = avcodec_decode_video(avctx, picture, &got_picture,
170                         in, inlen);
171
172         if ( bytes_decoded != inlen )
173         {
174                 fprintf(stderr,
175                         "codec_ffmpeg: decode: failed to decode whole frame %d / %d\n",
176                         bytes_decoded, inlen);
177                 return -1;
178         }
179
180         if ( !got_picture )
181         {
182                 fprintf(stderr,
183                         "codec_ffmpeg: decode: failed to get picture\n");
184                 return -1;
185         }
186
187         frame_to_frame_xlate(avctx, picture, outlen, out);
188
189         return 0;
190 }
191
192 static char *parse_slice_header(char * in, struct slice_header_t * slice_header)
193 {
194         slice_header->version     = in[0];
195         slice_header->source_id   = (in[1] << 8) | in[2];
196         slice_header->frame_index = in[3];
197         slice_header->slice_index = in[4];
198         slice_header->num_slices  = in[5];
199
200         if ( slice_header->version != 0 )
201         {
202                 fprintf(stderr,
203                         "codec_ffmpeg: decode: unknown slice header version %d\n",
204                         slice_header->version);
205                 return 0;
206         }
207
208         return in + 6;
209 }
210
211 static int decode_iaxc_slice(struct iaxc_video_codec * c, int inlen,
212                 char * in, int * outlen, char * out)
213 {
214         struct decoder_ctx *d = (struct decoder_ctx *) c->decstate;
215         struct slice_header_t * sh_saved = &d->slice_header;
216         struct slice_header_t sh_this;
217         char * inp;
218         int ret;
219
220         inp = parse_slice_header(in, &sh_this);
221
222         if ( !inp )
223                 return -1;
224
225         inlen -= inp - in;
226
227         if ( sh_this.source_id == sh_saved->source_id )
228         {
229                 unsigned char frame_delta;
230
231                 frame_delta = sh_this.frame_index - sh_saved->frame_index;
232
233                 if ( frame_delta > 20 )
234                 {
235                         /* This is an old slice. It's too late, we ignore it. */
236                         return 1;
237                 }
238                 else if ( frame_delta > 0 )
239                 {
240                         /* This slice belongs to a future frame */
241                         if ( sh_saved->slice_index > 0 )
242                         {
243                                 /* We have received slices for a previous
244                                  * frame (e.g. the one we were previously
245                                  * working on), so we go ahead and send this
246                                  * partial frame to the decoder and get setup
247                                  * for the new frame.
248                                  */
249
250                                 ret = pass_frame_to_decoder(d->avctx, d->picture,
251                                                 d->frame_size, d->frame_buf,
252                                                 outlen, out);
253
254                                 reset_decoder_frame_state(d);
255
256                                 if ( ret )
257                                         return -1;
258                         }
259
260                         sh_saved->frame_index = sh_this.frame_index;
261                 }
262         }
263         else
264         {
265                 sh_saved->source_id = sh_this.source_id;
266                 sh_saved->frame_index = sh_this.frame_index;
267                 sh_saved->slice_index = 0;
268                 d->frame_size = 0;
269         }
270
271         if ( c->fragsize * sh_this.slice_index + inlen > d->frame_buf_len )
272         {
273                 fprintf(stderr,
274                         "codec_ffmpeg: decode: slice overflows decoder frame buffer\n");
275                 return -1;
276         }
277
278         memcpy(d->frame_buf + c->fragsize * sh_this.slice_index,
279                         inp, inlen);
280         sh_saved->slice_index++;
281         d->frame_size = c->fragsize * sh_this.slice_index + inlen;
282
283         if ( sh_saved->slice_index < sh_this.num_slices )
284         {
285                 /* Do not decode yet, there are more slices coming for
286                  * this frame.
287                  */
288                 return 1;
289         }
290
291         ret = pass_frame_to_decoder(d->avctx, d->picture, d->frame_size,
292                         d->frame_buf, outlen, out);
293
294         reset_decoder_frame_state(d);
295
296         if ( ret )
297                 return -1;
298
299         return 0;
300 }
301
302 static int decode_rtp_slice(struct iaxc_video_codec * c,
303                   int inlen, char * in, int * outlen, char * out)
304 {
305         struct decoder_ctx *d = (struct decoder_ctx *) c->decstate;
306         int ret = 1;
307
308         while ( inlen )
309         {
310                 int bytes_decoded;
311                 int got_picture;
312
313                 bytes_decoded = avcodec_decode_video(d->avctx, d->picture,
314                                 &got_picture, (unsigned char *)in, inlen);
315
316                 if ( bytes_decoded < 0 )
317                 {
318                         fprintf(stderr,
319                                 "codec_ffmpeg: decode: error decoding frame\n");
320                         return -1;
321                 }
322
323                 inlen -= bytes_decoded;
324                 in += bytes_decoded;
325
326                 if ( got_picture && ret == 0)
327                 {
328                         fprintf(stderr,
329                                 "codec_ffmpeg: decode: unexpected second frame\n");
330                         return -1;
331                 }
332
333                 if ( got_picture )
334                 {
335                         frame_to_frame_xlate(d->avctx, d->picture, outlen, out);
336                         ret = 0;
337                 }
338         }
339
340         return ret;
341 }
342
343 static void slice_encoded_frame(struct slice_header_t * sh,
344                 struct slice_set_t * slice_set,
345                 unsigned char * in, int inlen, int fragsize)
346 {
347         sh->num_slices = slice_set->num_slices = (inlen - 1) / fragsize + 1;
348
349         for (sh->slice_index = 0; sh->slice_index < sh->num_slices;
350                         ++sh->slice_index)
351         {
352                 int slice_size = (sh->slice_index == sh->num_slices - 1) ?
353                         inlen % fragsize : fragsize;
354
355                 slice_set->size[sh->slice_index] = slice_size + 6;
356                 slice_set->data[sh->slice_index][0] = sh->version;
357                 slice_set->data[sh->slice_index][1] = sh->source_id >> 8;
358                 slice_set->data[sh->slice_index][2] = sh->source_id & 0xff;
359                 slice_set->data[sh->slice_index][3] = sh->frame_index;
360                 slice_set->data[sh->slice_index][4] = sh->slice_index;
361                 slice_set->data[sh->slice_index][5] = sh->num_slices;
362
363                 memcpy(&slice_set->data[sh->slice_index][6], in, slice_size);
364
365                 in += slice_size;
366         }
367
368         sh->frame_index++;
369 }
370
371 static int encode(struct iaxc_video_codec *c,
372                 int inlen, char * in, struct slice_set_t * slice_set)
373 {
374         struct encoder_ctx *e = (struct encoder_ctx *) c->encstate;
375         int encoded_size;
376
377         avcodec_get_frame_defaults(e->picture);
378
379         e->picture->data[0] = (unsigned char *)in;
380         e->picture->data[1] = (unsigned char *)in
381                 + e->avctx->width * e->avctx->height;
382         e->picture->data[2] = (unsigned char *)in
383                 + e->avctx->width * e->avctx->height * 5 / 4;
384
385         e->picture->linesize[0] = e->avctx->width;
386         e->picture->linesize[1] = e->avctx->width / 2;
387         e->picture->linesize[2] = e->avctx->width / 2;
388
389         /* TODO: investigate setting a real pts value */
390         e->picture->pts = AV_NOPTS_VALUE;
391
392         /* TODO: investigate quality */
393         e->picture->quality = 10;
394
395         g_slice_set = slice_set;
396         slice_set->num_slices = 0;
397
398         encoded_size = avcodec_encode_video(e->avctx,
399                         e->frame_buf, e->frame_buf_len, e->picture);
400
401         if (!encoded_size)
402         {
403                 fprintf(stderr, "codec_ffmpeg: encode failed\n");
404                 return -1;
405         }
406
407         slice_set->key_frame = e->avctx->coded_frame->key_frame;
408
409         /* This is paranoia, of course. */
410         g_slice_set = 0;
411
412         /* We are in one of two modes here.
413          *
414          * The first possibility is that the codec supports rtp
415          * packetization. In this case, the slice_set has already been
416          * filled via encode_rtp_callback() calls made during the call
417          * to avcodec_encode_video().
418          *
419          * The second possibility is that we have one big encoded frame
420          * that we need to slice-up ourselves.
421          */
422
423         if (!e->avctx->rtp_payload_size)
424                 slice_encoded_frame(&e->slice_header, slice_set,
425                                 e->frame_buf, encoded_size, c->fragsize);
426
427         return 0;
428 }
429
430 void encode_rtp_callback(struct AVCodecContext *avctx, void *data, int size,
431                      int mb_nb)
432 {
433         memcpy(&g_slice_set->data[g_slice_set->num_slices], data, size);
434         g_slice_set->size[g_slice_set->num_slices] = size;
435         g_slice_set->num_slices++;
436 }
437
438 struct iaxc_video_codec *codec_video_ffmpeg_new(int format, int w, int h,
439                                                      int framerate, int bitrate,
440                                                      int fragsize)
441 {
442         struct encoder_ctx *e;
443         struct decoder_ctx *d;
444         AVCodec *codec;
445         int ff_enc_id, ff_dec_id;
446         char *name;
447
448         struct iaxc_video_codec *c = calloc(sizeof(struct iaxc_video_codec), 1);
449
450         if (!c)
451         {
452                 fprintf(stderr,
453                         "codec_ffmpeg: failed to allocate video context\n");
454                 return NULL;
455         }
456
457         avcodec_init();
458         avcodec_register_all();
459
460         c->format = format;
461         c->width = w;
462         c->height = h;
463         c->framerate = framerate;
464         c->bitrate = bitrate;
465         /* TODO: Is a fragsize of zero valid? If so, there's a divide
466          * by zero error to contend with.
467          */
468         c->fragsize = fragsize;
469
470         c->encode = encode;
471         c->decode = decode_iaxc_slice;
472         c->destroy = destroy;
473
474         c->encstate = calloc(sizeof(struct encoder_ctx), 1);
475         if (!c->encstate)
476                 goto bail;
477         e = c->encstate;
478         e->avctx = avcodec_alloc_context();
479         if (!e->avctx)
480                 goto bail;
481         e->picture = avcodec_alloc_frame();
482         if (!e->picture)
483                 goto bail;
484         /* The idea here is that the encoded frame that will land in this
485          * buffer will be no larger than the size of an uncompressed 32-bit
486          * rgb frame.
487          *
488          * TODO: Is this assumption really valid?
489          */
490         e->frame_buf_len = w * h * 4;
491         e->frame_buf = malloc(e->frame_buf_len);
492         if (!e->frame_buf)
493                 goto bail;
494
495         c->decstate = calloc(sizeof(struct decoder_ctx), 1);
496         if (!c->decstate)
497                 goto bail;
498         d = c->decstate;
499         d->avctx = avcodec_alloc_context();
500         if (!d->avctx)
501                 goto bail;
502         d->picture = avcodec_alloc_frame();
503         if (!d->picture)
504                 goto bail;
505         d->frame_buf_len = e->frame_buf_len;
506         d->frame_buf = malloc(d->frame_buf_len);
507         if (!d->frame_buf)
508                 goto bail;
509
510         e->slice_header.version = 0;
511         srandom(time(0));
512         e->slice_header.source_id = random() & 0xffff;
513
514         e->avctx->time_base.num = 1;
515         e->avctx->time_base.den = framerate;
516
517         e->avctx->width = w;
518         e->avctx->height = h;
519
520         e->avctx->bit_rate = bitrate;
521
522         /* This determines how often i-frames are sent */
523         e->avctx->gop_size = framerate * 3;
524         e->avctx->pix_fmt = PIX_FMT_YUV420P;
525         e->avctx->has_b_frames = 0;
526
527         e->avctx->mb_qmin = e->avctx->qmin = 10;
528         e->avctx->mb_qmax = e->avctx->qmax = 10;
529
530         e->avctx->lmin = 2 * FF_QP2LAMBDA;
531         e->avctx->lmax = 10 * FF_QP2LAMBDA;
532         e->avctx->global_quality = FF_QP2LAMBDA * 2;
533         e->avctx->qblur = 0.5;
534         e->avctx->global_quality = 10;
535
536         e->avctx->flags |= CODEC_FLAG_PSNR;
537         e->avctx->flags |= CODEC_FLAG_QSCALE;
538
539         e->avctx->mb_decision = FF_MB_DECISION_SIMPLE;
540
541         ff_enc_id = ff_dec_id = map_iaxc_codec_to_avcodec(format);
542
543         /* Note, when fragsize is used (non-zero) ffmpeg will use a "best
544          * effort" strategy: the fragment size will be fragsize +/- 20%
545          */
546
547         switch (format)
548         {
549
550         case IAXC_FORMAT_H261:
551                 /* TODO: H261 only works with specific resolutions. */
552                 name = "H.261";
553                 break;
554
555         case IAXC_FORMAT_H263:
556                 /* TODO: H263 only works with specific resolutions. */
557                 name = "H.263";
558                 e->avctx->flags |= CODEC_FLAG_AC_PRED;
559                 if (fragsize)
560                 {
561                         c->decode = decode_rtp_slice;
562                         e->avctx->rtp_payload_size = fragsize;
563                         e->avctx->flags |=
564                                 CODEC_FLAG_TRUNCATED | CODEC_FLAG2_STRICT_GOP;
565                         e->avctx->rtp_callback = encode_rtp_callback;
566                         d->avctx->flags |= CODEC_FLAG_TRUNCATED;
567                 }
568                 break;
569
570         case IAXC_FORMAT_H263_PLUS:
571                 /* Although the encoder is CODEC_ID_H263P, the decoder
572                  * is the regular h.263, so we handle this special case
573                  * here.
574                  */
575                 ff_dec_id = CODEC_ID_H263;
576                 name = "H.263+";
577                 e->avctx->flags |= CODEC_FLAG_AC_PRED;
578                 if (fragsize)
579                 {
580                         c->decode = decode_rtp_slice;
581                         e->avctx->rtp_payload_size = fragsize;
582                         e->avctx->flags |=
583                                 CODEC_FLAG_TRUNCATED |
584                                 CODEC_FLAG_H263P_SLICE_STRUCT |
585                                 CODEC_FLAG2_STRICT_GOP |
586                                 CODEC_FLAG2_LOCAL_HEADER;
587                         e->avctx->rtp_callback = encode_rtp_callback;
588                         d->avctx->flags |= CODEC_FLAG_TRUNCATED;
589                 }
590                 break;
591
592         case IAXC_FORMAT_MPEG4:
593                 name = "MPEG4";
594                 c->decode = decode_rtp_slice;
595                 e->avctx->rtp_payload_size = fragsize;
596                 e->avctx->rtp_callback = encode_rtp_callback;
597                 e->avctx->flags |=
598                         CODEC_FLAG_TRUNCATED |
599                         CODEC_FLAG_H263P_SLICE_STRUCT |
600                         CODEC_FLAG2_STRICT_GOP |
601                         CODEC_FLAG2_LOCAL_HEADER;
602
603                 d->avctx->flags |= CODEC_FLAG_TRUNCATED;
604                 break;
605
606         case IAXC_FORMAT_H264:
607                 name = "H.264";
608
609                 /*
610                  * Encoder flags
611                  */
612
613                 /* Headers are not repeated */
614                 /* e->avctx->flags |= CODEC_FLAG_GLOBAL_HEADER; */
615
616                 /* Slower, less blocky */
617                 /* e->avctx->flags |= CODEC_FLAG_LOOP_FILTER; */
618
619                 e->avctx->flags |= CODEC_FLAG_PASS1;
620                 /* e->avctx->flags |= CODEC_FLAG_PASS2; */
621
622                 /* Compute psnr values at encode-time (avctx->error[]) */
623                 /* e->avctx->flags |= CODEC_FLAG_PSNR; */
624
625                 /* e->avctx->flags2 |= CODEC_FLAG2_8X8DCT; */
626
627                 /* Access Unit Delimiters */
628                 e->avctx->flags2 |= CODEC_FLAG2_AUD;
629
630                 /* Allow b-frames to be used as reference */
631                 /* e->avctx->flags2 |= CODEC_FLAG2_BPYRAMID; */
632
633                 /* b-frame rate distortion optimization */
634                 /* e->avctx->flags2 |= CODEC_FLAG2_BRDO; */
635
636                 /* e->avctx->flags2 |= CODEC_FLAG2_FASTPSKIP; */
637
638                 /* Multiple references per partition */
639                 /* e->avctx->flags2 |= CODEC_FLAG2_MIXED_REFS; */
640
641                 /* Weighted biprediction for b-frames */
642                 /* e->avctx->flags2 |= CODEC_FLAG2_WPRED; */
643
644                 /*
645                  * Decoder flags
646                  */
647
648                 /* Do not draw edges */
649                 /* d->avctx->flags |= CODEC_FLAG_EMU_EDGE; */
650
651                 /* Decode grayscale only */
652                 /* d->avctx->flags |= CODEC_FLAG_GRAY; */
653
654                 /* d->avctx->flags |= CODEC_FLAG_LOW_DELAY; */
655
656                 /* Allow input bitstream to be randomly truncated */
657                 /* d->avctx->flags |= CODEC_FLAG_TRUNCATED; */
658
659                 /* Allow out-of-spec speed tricks */
660                 /* d->avctx->flags2 |= CODEC_FLAG2_FAST; */
661                 break;
662
663         case IAXC_FORMAT_THEORA:
664                 /* TODO: ffmpeg only has a theora decoder. Until it has
665                  * an encoder also, we cannot use ffmpeg for theora.
666                  */
667                 name = "Theora";
668                 break;
669
670         default:
671                 fprintf(stderr, "codec_ffmpeg: unsupported format (0x%08x)\n",
672                                 format);
673                 goto bail;
674         }
675
676         strcpy(c->name, "ffmpeg-");
677         strncat(c->name, name, sizeof(c->name));
678
679         /* Get the codecs */
680         codec = avcodec_find_encoder(ff_enc_id);
681         if (!codec)
682         {
683                 iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
684                              "codec_ffmpeg: cannot find encoder %d\n",
685                              ff_enc_id);
686                 goto bail;
687         }
688
689         if (avcodec_open(e->avctx, codec))
690         {
691                 iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
692                              "codec_ffmpeg: cannot open encoder %s\n", name);
693                 goto bail;
694         }
695
696         codec = avcodec_find_decoder(ff_dec_id);
697         if (!codec)
698         {
699                 iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
700                              "codec_ffmpeg: cannot find decoder %d\n",
701                              ff_dec_id);
702                 goto bail;
703         }
704         if (avcodec_open(d->avctx, codec))
705         {
706                 iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
707                              "codec_ffmpeg: cannot open decoder %s\n", name);
708                 goto bail;
709         }
710
711         {
712                 enum PixelFormat fmts[] = { PIX_FMT_YUV420P, -1 };
713                 if (d->avctx->get_format(d->avctx, fmts) != PIX_FMT_YUV420P)
714                 {
715                         iaxci_usermsg(IAXC_TEXT_TYPE_ERROR,
716                                         "codec_ffmpeg: cannot set decode format to YUV420P\n");
717                         goto bail;
718                 }
719         }
720
721         return c;
722
723 bail:
724         destroy(c);
725         return 0;
726 }
727
728 int codec_video_ffmpeg_check_codec(int format)
729 {
730         AVCodec *codec;
731         enum CodecID codec_id;
732
733         /* These functions are idempotent, so it is okay that we
734          * may call them elsewhere at a different time.
735          */
736         avcodec_init();
737         avcodec_register_all();
738
739         codec_id = map_iaxc_codec_to_avcodec(format);
740
741         if (codec_id == CODEC_ID_NONE)
742                 return 0;
743
744         codec = avcodec_find_encoder(codec_id);
745
746         return codec ? 1 : 0;
747 }
748