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
map_iaxc_codec_to_avcodec(int format)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
destroy(struct iaxc_video_codec * c)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
reset_decoder_frame_state(struct decoder_ctx * d)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
frame_to_frame_xlate(AVCodecContext * avctx,AVFrame * picture,int * outlen,char * out)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
pass_frame_to_decoder(AVCodecContext * avctx,AVFrame * picture,int inlen,unsigned char * in,int * outlen,char * out)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
parse_slice_header(char * in,struct slice_header_t * slice_header)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
decode_iaxc_slice(struct iaxc_video_codec * c,int inlen,char * in,int * outlen,char * out)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
decode_rtp_slice(struct iaxc_video_codec * c,int inlen,char * in,int * outlen,char * out)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
slice_encoded_frame(struct slice_header_t * sh,struct slice_set_t * slice_set,unsigned char * in,int inlen,int fragsize)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
encode(struct iaxc_video_codec * c,int inlen,char * in,struct slice_set_t * slice_set)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
encode_rtp_callback(struct AVCodecContext * avctx,void * data,int size,int mb_nb)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
codec_video_ffmpeg_new(int format,int w,int h,int framerate,int bitrate,int fragsize)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
codec_video_ffmpeg_check_codec(int format)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
749