1 /*****************************************************************************
2 * daala.c: daala codec module making use of libdaala.
3 *****************************************************************************
4 * Copyright (C) 2014 VLC authors and VideoLAN
5 *
6 * Authors: Tristan Matthews <le.businessman@gmail.com>
7 * * Based on theora.c by: Gildas Bazin <gbazin@videolan.org>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
23
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
34 #include <vlc_input.h>
35 #include "../demux/xiph.h"
36
37 #include <daala/codec.h>
38 #include <daala/daaladec.h>
39 #ifdef ENABLE_SOUT
40 #include <daala/daalaenc.h>
41 #endif
42
43 #include <limits.h>
44
45 /*****************************************************************************
46 * decoder_sys_t : daala decoder descriptor
47 *****************************************************************************/
48 struct decoder_sys_t
49 {
50 /* Module mode */
51 bool b_packetizer;
52
53 /*
54 * Input properties
55 */
56 bool b_has_headers;
57
58 /*
59 * Daala properties
60 */
61 daala_info di; /* daala bitstream settings */
62 daala_comment dc; /* daala comment information */
63 daala_dec_ctx *dcx; /* daala decoder context */
64
65 /*
66 * Decoding properties
67 */
68 bool b_decoded_first_keyframe;
69
70 /*
71 * Common properties
72 */
73 mtime_t i_pts;
74 };
75
76 /*****************************************************************************
77 * Local prototypes
78 *****************************************************************************/
79 static int OpenDecoder ( vlc_object_t * );
80 static int OpenPacketizer( vlc_object_t * );
81 static void CloseDecoder ( vlc_object_t * );
82
83 static int DecodeVideo( decoder_t *p_dec, block_t *p_block );
84 static block_t *Packetize ( decoder_t *, block_t ** );
85 static int ProcessHeaders( decoder_t * );
86 static void *ProcessPacket ( decoder_t *, daala_packet *, block_t * );
87
88 static picture_t *DecodePacket( decoder_t *, daala_packet * );
89
90 static void ParseDaalaComments( decoder_t * );
91 static void daala_CopyPicture( picture_t *, daala_image * );
92
93 #ifdef ENABLE_SOUT
94 static int OpenEncoder( vlc_object_t *p_this );
95 static void CloseEncoder( vlc_object_t *p_this );
96 static block_t *Encode( encoder_t *p_enc, picture_t *p_pict );
97
98 static const char *const enc_chromafmt_list[] = {
99 "420", "444"
100 };
101 static const char *const enc_chromafmt_list_text[] = {
102 "4:2:0", "4:4:4"
103 };
104 #endif
105
106 /*****************************************************************************
107 * Module descriptor
108 *****************************************************************************/
109 #define ENC_QUALITY_TEXT N_("Encoding quality")
110 #define ENC_QUALITY_LONGTEXT N_( \
111 "Enforce a quality between 0 (lossless) and 511 (worst)." )
112 #define ENC_KEYINT_TEXT N_("Keyframe interval")
113 #define ENC_KEYINT_LONGTEXT N_( \
114 "Enforce a keyframe interval between 1 and 1000." )
115
116 vlc_module_begin ()
117 set_category( CAT_INPUT )
118 set_subcategory( SUBCAT_INPUT_VCODEC )
119 set_shortname( "Daala" )
120 set_description( N_("Daala video decoder") )
121 set_capability( "video decoder", 100 )
122 set_callbacks( OpenDecoder, CloseDecoder )
123 add_shortcut( "daala" )
124 add_submodule ()
125 set_description( N_("Daala video packetizer") )
126 set_capability( "packetizer", 100 )
127 set_callbacks( OpenPacketizer, CloseDecoder )
128 add_shortcut( "daala" )
129
130 #ifdef ENABLE_SOUT
131 add_submodule ()
132 set_description( N_("Daala video encoder") )
133 set_capability( "encoder", 150 )
134 set_callbacks( OpenEncoder, CloseEncoder )
135 add_shortcut( "daala" )
136
137 # define ENC_CFG_PREFIX "sout-daala-"
138 add_integer_with_range( ENC_CFG_PREFIX "quality", 10, 0, 511,
139 ENC_QUALITY_TEXT, ENC_QUALITY_LONGTEXT, false )
140 add_integer_with_range( ENC_CFG_PREFIX "keyint", 256, 1, 1000,
141 ENC_KEYINT_TEXT, ENC_KEYINT_LONGTEXT, false )
142
143 # define ENC_CHROMAFMT_TEXT N_("Chroma format")
144 # define ENC_CHROMAFMT_LONGTEXT N_("Picking chroma format will force a " \
145 "conversion of the video into that format")
146
147 add_string( ENC_CFG_PREFIX "chroma-fmt", "420", ENC_CHROMAFMT_TEXT,
148 ENC_CHROMAFMT_LONGTEXT, false )
149 change_string_list( enc_chromafmt_list, enc_chromafmt_list_text )
150 #endif
151 vlc_module_end ()
152
153 #ifdef ENABLE_SOUT
154 static const char *const ppsz_enc_options[] = {
155 "quality", "keyint", "chroma-fmt", NULL
156 };
157 #endif
158
159 /*****************************************************************************
160 * OpenDecoder: probe the decoder and return score
161 *****************************************************************************/
OpenDecoder(vlc_object_t * p_this)162 static int OpenDecoder( vlc_object_t *p_this )
163 {
164 decoder_t *p_dec = (decoder_t*)p_this;
165 decoder_sys_t *p_sys;
166
167 if( p_dec->fmt_in.i_codec != VLC_CODEC_DAALA )
168 {
169 return VLC_EGENERIC;
170 }
171
172 /* Allocate the memory needed to store the decoder's structure */
173 p_sys = malloc(sizeof(*p_sys));
174 if( p_sys == NULL )
175 return VLC_ENOMEM;
176
177 p_dec->p_sys = p_sys;
178 p_dec->p_sys->b_packetizer = false;
179 p_sys->b_has_headers = false;
180 p_sys->i_pts = VLC_TS_INVALID;
181 p_sys->b_decoded_first_keyframe = false;
182 p_sys->dcx = NULL;
183
184 /* Set output properties */
185 p_dec->fmt_out.i_codec = VLC_CODEC_I420;
186
187 /* Set callbacks */
188 p_dec->pf_decode = DecodeVideo;
189 p_dec->pf_packetize = Packetize;
190
191 /* Init supporting Daala structures needed in header parsing */
192 daala_comment_init( &p_sys->dc );
193 daala_info_init( &p_sys->di );
194
195 return VLC_SUCCESS;
196 }
197
OpenPacketizer(vlc_object_t * p_this)198 static int OpenPacketizer( vlc_object_t *p_this )
199 {
200 decoder_t *p_dec = (decoder_t*)p_this;
201
202 int i_ret = OpenDecoder( p_this );
203
204 if( i_ret == VLC_SUCCESS )
205 {
206 p_dec->p_sys->b_packetizer = true;
207 p_dec->fmt_out.i_codec = VLC_CODEC_DAALA;
208 }
209
210 return i_ret;
211 }
212
213 /****************************************************************************
214 * DecodeBlock: the whole thing
215 ****************************************************************************
216 * This function must be fed with Daala packets.
217 ****************************************************************************/
DecodeBlock(decoder_t * p_dec,block_t * p_block)218 static void *DecodeBlock( decoder_t *p_dec, block_t *p_block )
219 {
220 decoder_sys_t *p_sys = p_dec->p_sys;
221 daala_packet dpacket;
222
223 /* Block to Daala packet */
224 dpacket.packet = p_block->p_buffer;
225 dpacket.bytes = p_block->i_buffer;
226 dpacket.granulepos = p_block->i_dts;
227 dpacket.b_o_s = 0;
228 dpacket.e_o_s = 0;
229 dpacket.packetno = 0;
230
231 /* Check for headers */
232 if( !p_sys->b_has_headers )
233 {
234 if( ProcessHeaders( p_dec ) )
235 {
236 block_Release( p_block );
237 return NULL;
238 }
239 p_sys->b_has_headers = true;
240 }
241
242 /* If we haven't seen a single keyframe yet, set to preroll,
243 * otherwise we'll get display artifacts. (This is impossible
244 * in the general case, but can happen if e.g. we play a network stream
245 * using a timed URL, such that the server doesn't start the video with a
246 * keyframe). */
247 if( !p_sys->b_decoded_first_keyframe )
248 p_block->i_flags |= BLOCK_FLAG_PREROLL; /* Wait until we've decoded the first keyframe */
249
250 return ProcessPacket( p_dec, &dpacket, p_block );
251 }
252
DecodeVideo(decoder_t * p_dec,block_t * p_block)253 static int DecodeVideo( decoder_t *p_dec, block_t *p_block )
254 {
255 if( p_block == NULL ) /* No Drain */
256 return VLCDEC_SUCCESS;
257
258 picture_t *p_pic = DecodeBlock( p_dec, p_block );
259 if( p_pic != NULL )
260 decoder_QueueVideo( p_dec, p_pic );
261 return VLCDEC_SUCCESS;
262 }
263
Packetize(decoder_t * p_dec,block_t ** pp_block)264 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
265 {
266 if( pp_block == NULL ) /* No Drain */
267 return NULL;
268 block_t *p_block = *pp_block; *pp_block = NULL;
269 if( p_block == NULL )
270 return NULL;
271 return DecodeBlock( p_dec, p_block );
272 }
273
274 /*****************************************************************************
275 * ProcessHeaders: process Daala headers.
276 *****************************************************************************/
ProcessHeaders(decoder_t * p_dec)277 static int ProcessHeaders( decoder_t *p_dec )
278 {
279 int ret = VLC_SUCCESS;
280 decoder_sys_t *p_sys = p_dec->p_sys;
281 daala_packet dpacket;
282 daala_setup_info *ds = NULL; /* daala setup information */
283
284 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
285 const void *pp_data[XIPH_MAX_HEADER_COUNT];
286 unsigned i_count;
287 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
288 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
289 return VLC_EGENERIC;
290 if( i_count < 3 )
291 return VLC_EGENERIC;
292
293 dpacket.granulepos = -1;
294 dpacket.e_o_s = 0;
295 dpacket.packetno = 0;
296
297 /* Take care of the initial info header */
298 dpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
299 dpacket.bytes = pi_size[0];
300 dpacket.packet = (void *)pp_data[0];
301 if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &dpacket ) < 0 )
302 {
303 msg_Err( p_dec, "this bitstream does not contain Daala video data" );
304 ret = VLC_EGENERIC;
305 goto cleanup;
306 }
307
308 /* Set output properties */
309 if( !p_sys->b_packetizer )
310 {
311 if( p_sys->di.plane_info[0].xdec == 0 && p_sys->di.plane_info[0].ydec == 0 &&
312 p_sys->di.plane_info[1].xdec == 1 && p_sys->di.plane_info[1].ydec == 1 &&
313 p_sys->di.plane_info[2].xdec == 1 && p_sys->di.plane_info[2].ydec == 1 )
314 {
315 p_dec->fmt_out.i_codec = VLC_CODEC_I420;
316 }
317 else if( p_sys->di.plane_info[0].xdec == 0 && p_sys->di.plane_info[0].ydec == 0 &&
318 p_sys->di.plane_info[1].xdec == 0 && p_sys->di.plane_info[1].ydec == 0 &&
319 p_sys->di.plane_info[2].xdec == 0 && p_sys->di.plane_info[2].ydec == 0 )
320 {
321 p_dec->fmt_out.i_codec = VLC_CODEC_I444;
322 }
323 else
324 {
325 msg_Err( p_dec, "unknown chroma in daala sample" );
326 }
327 }
328
329 p_dec->fmt_out.video.i_width = p_sys->di.pic_width;
330 p_dec->fmt_out.video.i_height = p_sys->di.pic_height;
331 if( p_sys->di.pic_width && p_sys->di.pic_height )
332 {
333 p_dec->fmt_out.video.i_visible_width = p_sys->di.pic_width;
334 p_dec->fmt_out.video.i_visible_height = p_sys->di.pic_height;
335 }
336
337 if( p_sys->di.pixel_aspect_denominator && p_sys->di.pixel_aspect_numerator )
338 {
339 p_dec->fmt_out.video.i_sar_num = p_sys->di.pixel_aspect_numerator;
340 p_dec->fmt_out.video.i_sar_den = p_sys->di.pixel_aspect_denominator;
341 }
342 else
343 {
344 p_dec->fmt_out.video.i_sar_num = 1;
345 p_dec->fmt_out.video.i_sar_den = 1;
346 }
347
348 if( p_sys->di.timebase_numerator > 0 && p_sys->di.timebase_denominator > 0 )
349 {
350 p_dec->fmt_out.video.i_frame_rate = p_sys->di.timebase_numerator;
351 p_dec->fmt_out.video.i_frame_rate_base = p_sys->di.timebase_denominator;
352 }
353
354 msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content ",
355 p_sys->di.pic_width, p_sys->di.pic_height,
356 (double)p_sys->di.timebase_numerator/p_sys->di.timebase_denominator );
357
358 /* The next packet in order is the comments header */
359 dpacket.b_o_s = 0;
360 dpacket.bytes = pi_size[1];
361 dpacket.packet = (void *)pp_data[1];
362
363 if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &dpacket ) < 0 )
364 {
365 msg_Err( p_dec, "Daala comment header is corrupted" );
366 ret = VLC_EGENERIC;
367 goto cleanup;
368 }
369
370 ParseDaalaComments( p_dec );
371
372 /* The next packet in order is the setup header
373 * We need to watch out that this packet is not missing as a
374 * missing or corrupted header is fatal. */
375 dpacket.b_o_s = 0;
376 dpacket.bytes = pi_size[2];
377 dpacket.packet = (void *)pp_data[2];
378 if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &dpacket ) < 0 )
379 {
380 msg_Err( p_dec, "Daala setup header is corrupted" );
381 ret = VLC_EGENERIC;
382 goto cleanup;
383 }
384
385 if( !p_sys->b_packetizer )
386 {
387 /* We have all the headers, initialize decoder */
388 if ( ( p_sys->dcx = daala_decode_create( &p_sys->di, ds ) ) == NULL )
389 {
390 msg_Err( p_dec, "Could not allocate Daala decoder" );
391 ret = VLC_EGENERIC;
392 goto cleanup;
393 }
394 }
395 else
396 {
397 void* p_extra = realloc( p_dec->fmt_out.p_extra,
398 p_dec->fmt_in.i_extra );
399 if( unlikely( p_extra == NULL ) )
400 {
401 ret = VLC_ENOMEM;
402 goto cleanup;
403 }
404 p_dec->fmt_out.p_extra = p_extra;
405 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
406 memcpy( p_dec->fmt_out.p_extra,
407 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
408 }
409
410 cleanup:
411 /* Clean up the decoder setup info... we're done with it */
412 daala_setup_free( ds );
413
414 return ret;
415 }
416
417 /*****************************************************************************
418 * ProcessPacket: processes a daala packet.
419 *****************************************************************************/
ProcessPacket(decoder_t * p_dec,daala_packet * p_dpacket,block_t * p_block)420 static void *ProcessPacket( decoder_t *p_dec, daala_packet *p_dpacket,
421 block_t *p_block )
422 {
423 decoder_sys_t *p_sys = p_dec->p_sys;
424 void *p_buf;
425
426 if( ( p_block->i_flags&(BLOCK_FLAG_CORRUPTED) ) != 0 )
427 {
428 /* Don't send the the first packet after a discontinuity to
429 * daala_decode, otherwise we get purple/green display artifacts
430 * appearing in the video output */
431 block_Release(p_block);
432 return NULL;
433 }
434
435 /* Date management */
436 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
437 {
438 p_sys->i_pts = p_block->i_pts;
439 }
440
441 if( p_sys->b_packetizer )
442 {
443 /* Date management */
444 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
445
446 p_block->i_length = p_sys->i_pts - p_block->i_pts;
447
448 p_buf = p_block;
449 }
450 else
451 {
452 p_buf = DecodePacket( p_dec, p_dpacket );
453 block_Release( p_block );
454 }
455
456 /* Date management */
457 p_sys->i_pts += ( CLOCK_FREQ * p_sys->di.timebase_denominator /
458 p_sys->di.timebase_numerator ); /* 1 frame per packet */
459
460 return p_buf;
461 }
462
463 /*****************************************************************************
464 * DecodePacket: decodes a Daala packet.
465 *****************************************************************************/
DecodePacket(decoder_t * p_dec,daala_packet * p_dpacket)466 static picture_t *DecodePacket( decoder_t *p_dec, daala_packet *p_dpacket )
467 {
468 decoder_sys_t *p_sys = p_dec->p_sys;
469 picture_t *p_pic;
470 daala_image ycbcr;
471
472 if (daala_decode_packet_in( p_sys->dcx, p_dpacket ) < 0)
473 return NULL; /* bad packet */
474
475 if (!daala_decode_img_out( p_sys->dcx, &ycbcr ))
476 return NULL;
477
478 /* Check for keyframe */
479 if( daala_packet_iskeyframe( p_dpacket ) )
480 p_sys->b_decoded_first_keyframe = true;
481
482 /* Get a new picture */
483 if( decoder_UpdateVideoFormat( p_dec ) )
484 return NULL;
485 p_pic = decoder_NewPicture( p_dec );
486 if( !p_pic ) return NULL;
487
488 daala_CopyPicture( p_pic, &ycbcr );
489
490 p_pic->date = p_sys->i_pts;
491
492 return p_pic;
493 }
494
495 /*****************************************************************************
496 * ParseDaalaComments:
497 *****************************************************************************/
ParseDaalaComments(decoder_t * p_dec)498 static void ParseDaalaComments( decoder_t *p_dec )
499 {
500 char *psz_name, *psz_value, *psz_comment;
501 /* Regarding the daala_comment structure: */
502
503 /* The metadata is stored as a series of (tag, value) pairs, in
504 length-encoded string vectors. The first occurrence of the '='
505 character delimits the tag and value. A particular tag may
506 occur more than once, and order is significant. The character
507 set encoding for the strings is always UTF-8, but the tag names
508 are limited to ASCII, and treated as case-insensitive. See the
509 Theora specification, Section 6.3.3 for details. */
510
511 /* In filling in this structure, daala_decode_header_in() will
512 null-terminate the user_comment strings for safety. However,
513 the bitstream format itself treats them as 8-bit clean vectors,
514 possibly containing null characters, and so the length array
515 should be treated as their authoritative length. */
516 for ( int i = 0; i < p_dec->p_sys->dc.comments; i++ )
517 {
518 int clen = p_dec->p_sys->dc.comment_lengths[i];
519 if ( clen <= 0 || clen >= INT_MAX ) { continue; }
520 psz_comment = malloc( clen + 1 );
521 if( !psz_comment )
522 break;
523 memcpy( (void*)psz_comment, (void*)p_dec->p_sys->dc.user_comments[i], clen + 1 );
524 psz_comment[clen] = '\0';
525
526 psz_name = psz_comment;
527 psz_value = strchr( psz_comment, '=' );
528 if( psz_value )
529 {
530 *psz_value = '\0';
531 psz_value++;
532
533 if( !p_dec->p_description )
534 p_dec->p_description = vlc_meta_New();
535 /* TODO: Since psz_value can contain NULLs see if there is an
536 * instance where we need to preserve the full length of this string */
537 if( p_dec->p_description )
538 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
539 }
540 free( psz_comment );
541 }
542 }
543
544 /*****************************************************************************
545 * CloseDecoder: daala decoder destruction
546 *****************************************************************************/
CloseDecoder(vlc_object_t * p_this)547 static void CloseDecoder( vlc_object_t *p_this )
548 {
549 decoder_t *p_dec = (decoder_t *)p_this;
550 decoder_sys_t *p_sys = p_dec->p_sys;
551
552 daala_info_clear(&p_sys->di);
553 daala_comment_clear(&p_sys->dc);
554 daala_decode_free(p_sys->dcx);
555 free( p_sys );
556 }
557
558 /*****************************************************************************
559 * daala_CopyPicture: copy a picture from daala internal buffers to a
560 * picture_t structure.
561 *****************************************************************************/
daala_CopyPicture(picture_t * p_pic,daala_image * ycbcr)562 static void daala_CopyPicture( picture_t *p_pic,
563 daala_image *ycbcr )
564 {
565 const int i_planes = p_pic->i_planes < 3 ? p_pic->i_planes : 3;
566 for( int i_plane = 0; i_plane < i_planes; i_plane++ )
567 {
568 const int i_total_lines = __MIN(p_pic->p[i_plane].i_lines,
569 ycbcr->height >> ycbcr->planes[i_plane].ydec);
570 uint8_t *p_dst = p_pic->p[i_plane].p_pixels;
571 uint8_t *p_src = ycbcr->planes[i_plane].data;
572 const int i_dst_stride = p_pic->p[i_plane].i_pitch;
573 const int i_src_stride = ycbcr->planes[i_plane].ystride;
574 for( int i_line = 0; i_line < i_total_lines; i_line++ )
575 {
576 memcpy( p_dst, p_src, i_src_stride );
577 p_src += i_src_stride;
578 p_dst += i_dst_stride;
579 }
580 }
581 }
582
583 #ifdef ENABLE_SOUT
584 struct encoder_sys_t
585 {
586 daala_info di; /* daala bitstream settings */
587 daala_comment dc; /* daala comment header */
588 daala_enc_ctx *dcx; /* daala context */
589 };
590
OpenEncoder(vlc_object_t * p_this)591 static int OpenEncoder( vlc_object_t *p_this )
592 {
593 encoder_t *p_enc = (encoder_t *)p_this;
594 encoder_sys_t *p_sys;
595 daala_packet header;
596 int status;
597
598 if( p_enc->fmt_out.i_codec != VLC_CODEC_DAALA &&
599 !p_enc->obj.force )
600 {
601 return VLC_EGENERIC;
602 }
603
604 /* Allocate the memory needed to store the encoder's structure */
605 p_sys = malloc( sizeof( encoder_sys_t ) );
606 if( !p_sys )
607 return VLC_ENOMEM;
608 p_enc->p_sys = p_sys;
609
610 p_enc->pf_encode_video = Encode;
611 p_enc->fmt_in.i_codec = VLC_CODEC_I420;
612 p_enc->fmt_out.i_codec = VLC_CODEC_DAALA;
613
614 config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
615
616 char *psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX "chroma-fmt" );
617 uint32_t i_codec;
618 if( !psz_tmp ) {
619 free(p_sys);
620 return VLC_ENOMEM;
621 } else {
622 if( !strcmp( psz_tmp, "420" ) ) {
623 i_codec = VLC_CODEC_I420;
624 }
625 else if( !strcmp( psz_tmp, "444" ) ) {
626 i_codec = VLC_CODEC_I444;
627 }
628 else {
629 msg_Err( p_enc, "Invalid chroma format: %s", psz_tmp );
630 free( psz_tmp );
631 free( p_sys );
632 return VLC_EGENERIC;
633 }
634 free( psz_tmp );
635 p_enc->fmt_in.i_codec = i_codec;
636 /* update bits_per_pixel */
637 video_format_Setup(&p_enc->fmt_in.video, i_codec,
638 p_enc->fmt_in.video.i_width,
639 p_enc->fmt_in.video.i_height,
640 p_enc->fmt_in.video.i_visible_width,
641 p_enc->fmt_in.video.i_visible_height,
642 p_enc->fmt_in.video.i_sar_num,
643 p_enc->fmt_in.video.i_sar_den);
644 }
645
646 daala_info_init( &p_sys->di );
647
648 p_sys->di.pic_width = p_enc->fmt_in.video.i_visible_width;
649 p_sys->di.pic_height = p_enc->fmt_in.video.i_visible_height;
650
651 p_sys->di.nplanes = 3;
652 for (int i = 0; i < p_sys->di.nplanes; i++)
653 {
654 p_sys->di.plane_info[i].xdec = i > 0 && i_codec != VLC_CODEC_I444;
655 p_sys->di.plane_info[i].ydec = i_codec == VLC_CODEC_I420 ?
656 p_sys->di.plane_info[i].xdec : 0;
657 }
658 p_sys->di.frame_duration = 1;
659
660 if( !p_enc->fmt_in.video.i_frame_rate ||
661 !p_enc->fmt_in.video.i_frame_rate_base )
662 {
663 p_sys->di.timebase_numerator = 25;
664 p_sys->di.timebase_denominator = 1;
665 }
666 else
667 {
668 p_sys->di.timebase_numerator = p_enc->fmt_in.video.i_frame_rate;
669 p_sys->di.timebase_denominator = p_enc->fmt_in.video.i_frame_rate_base;
670 }
671
672 if( p_enc->fmt_in.video.i_sar_num > 0 && p_enc->fmt_in.video.i_sar_den > 0 )
673 {
674 unsigned i_dst_num, i_dst_den;
675 vlc_ureduce( &i_dst_num, &i_dst_den,
676 p_enc->fmt_in.video.i_sar_num,
677 p_enc->fmt_in.video.i_sar_den, 0 );
678 p_sys->di.pixel_aspect_numerator = i_dst_num;
679 p_sys->di.pixel_aspect_denominator = i_dst_den;
680 }
681 else
682 {
683 p_sys->di.pixel_aspect_numerator = 4;
684 p_sys->di.pixel_aspect_denominator = 3;
685 }
686
687 p_sys->di.keyframe_rate = var_GetInteger( p_enc, ENC_CFG_PREFIX "keyint" );
688
689 daala_enc_ctx *dcx;
690 p_sys->dcx = dcx = daala_encode_create( &p_sys->di );
691 if( !dcx )
692 {
693 free( p_sys );
694 return VLC_ENOMEM;
695 }
696
697 daala_comment_init( &p_sys->dc );
698
699 int i_quality = var_GetInteger( p_enc, ENC_CFG_PREFIX "quality" );
700 daala_encode_ctl( dcx, OD_SET_QUANT, &i_quality, sizeof(i_quality) );
701
702 /* Create and store headers */
703 while( ( status = daala_encode_flush_header( dcx, &p_sys->dc, &header ) ) )
704 {
705 if ( status < 0 )
706 {
707 CloseEncoder( p_this );
708 return VLC_EGENERIC;
709 }
710 if( xiph_AppendHeaders( &p_enc->fmt_out.i_extra,
711 &p_enc->fmt_out.p_extra, header.bytes,
712 header.packet ) )
713 {
714 p_enc->fmt_out.i_extra = 0;
715 p_enc->fmt_out.p_extra = NULL;
716 }
717 }
718 return VLC_SUCCESS;
719 }
720
Encode(encoder_t * p_enc,picture_t * p_pict)721 static block_t *Encode( encoder_t *p_enc, picture_t *p_pict )
722 {
723 encoder_sys_t *p_sys = p_enc->p_sys;
724 daala_packet dpacket;
725 block_t *p_block;
726 daala_image img;
727
728 if( !p_pict ) return NULL;
729
730 const int i_width = p_sys->di.pic_width;
731 const int i_height = p_sys->di.pic_height;
732
733 /* Sanity check */
734 if( p_pict->p[0].i_pitch < i_width ||
735 p_pict->p[0].i_lines < i_height )
736 {
737 msg_Err( p_enc, "frame is smaller than encoding size"
738 "(%ix%i->%ix%i) -> dropping frame",
739 p_pict->p[0].i_pitch, p_pict->p[0].i_lines,
740 i_width, i_height );
741 return NULL;
742 }
743
744 /* Daala is a one-frame-in, one-frame-out system. Submit a frame
745 * for compression and pull out the packet. */
746
747 img.nplanes = p_sys->di.nplanes;
748 img.width = i_width;
749 img.height = i_height;
750 for( int i = 0; i < img.nplanes; i++ )
751 {
752 img.planes[i].data = p_pict->p[i].p_pixels;
753 img.planes[i].xdec = p_sys->di.plane_info[i].xdec;
754 img.planes[i].ydec = p_sys->di.plane_info[i].ydec;
755 img.planes[i].xstride = 1;
756 img.planes[i].ystride = p_pict->p[i].i_pitch;
757 img.planes[i].bitdepth = 8; /*FIXME: support higher bit depths*/
758 }
759
760 if( daala_encode_img_in( p_sys->dcx, &img, 0 ) < 0 )
761 {
762 msg_Warn( p_enc, "failed encoding a frame" );
763 return NULL;
764 }
765
766 daala_encode_packet_out( p_sys->dcx, 0, &dpacket );
767
768 /* Daala packet to block */
769 p_block = block_Alloc( dpacket.bytes );
770 memcpy( p_block->p_buffer, dpacket.packet, dpacket.bytes );
771 p_block->i_dts = p_block->i_pts = p_pict->date;
772
773 if( daala_packet_iskeyframe( &dpacket ) )
774 p_block->i_flags |= BLOCK_FLAG_TYPE_I;
775
776 return p_block;
777 }
778
CloseEncoder(vlc_object_t * p_this)779 static void CloseEncoder( vlc_object_t *p_this )
780 {
781 encoder_t *p_enc = (encoder_t *)p_this;
782 encoder_sys_t *p_sys = p_enc->p_sys;
783
784 daala_info_clear(&p_sys->di);
785 daala_comment_clear(&p_sys->dc);
786 daala_encode_free(p_sys->dcx);
787 free( p_sys );
788 }
789 #endif
790