daala: fix bit-depth issue in encoding
[vlc.git] / modules / codec / daala.c
blob41a1b6cd9ff1930dcb49912949c5d934bb6ecffa
1 /*****************************************************************************
2 * daala.c: daala codec module making use of libdaala.
3 *****************************************************************************
4 * Copyright (C) 2014 VLC authors and VideoLAN
6 * Authors: Tristan Matthews <le.businessman@gmail.com>
7 * * Based on theora.c by: Gildas Bazin <gbazin@videolan.org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
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"
37 #include <daala/codec.h>
38 #include <daala/daaladec.h>
39 #ifdef ENABLE_SOUT
40 #include <daala/daalaenc.h>
41 #endif
43 #include <limits.h>
45 /*****************************************************************************
46 * decoder_sys_t : daala decoder descriptor
47 *****************************************************************************/
48 struct decoder_sys_t
50 /* Module mode */
51 bool b_packetizer;
54 * Input properties
56 bool b_has_headers;
59 * Daala properties
61 daala_info di; /* daala bitstream settings */
62 daala_comment dc; /* daala comment information */
63 daala_dec_ctx *dcx; /* daala decoder context */
66 * Decoding properties
68 bool b_decoded_first_keyframe;
71 * Common properties
73 mtime_t i_pts;
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 * );
83 static void *DecodeBlock ( decoder_t *, block_t ** );
84 static int ProcessHeaders( decoder_t * );
85 static void *ProcessPacket ( decoder_t *, daala_packet *, block_t ** );
87 static picture_t *DecodePacket( decoder_t *, daala_packet * );
89 static void ParseDaalaComments( decoder_t * );
90 static void daala_CopyPicture( picture_t *, daala_image * );
92 #ifdef ENABLE_SOUT
93 static int OpenEncoder( vlc_object_t *p_this );
94 static void CloseEncoder( vlc_object_t *p_this );
95 static block_t *Encode( encoder_t *p_enc, picture_t *p_pict );
97 static const char *const enc_chromafmt_list[] = {
98 "420", "444"
100 static const char *const enc_chromafmt_list_text[] = {
101 "4:2:0", "4:4:4"
103 #endif
105 /*****************************************************************************
106 * Module descriptor
107 *****************************************************************************/
108 #define ENC_QUALITY_TEXT N_("Encoding quality")
109 #define ENC_QUALITY_LONGTEXT N_( \
110 "Enforce a quality between 0 (lossless) and 511 (worst)." )
111 #define ENC_KEYINT_TEXT N_("Keyframe interval")
112 #define ENC_KEYINT_LONGTEXT N_( \
113 "Enforce a keyframe interval between 1 and 1000." )
115 vlc_module_begin ()
116 set_category( CAT_INPUT )
117 set_subcategory( SUBCAT_INPUT_VCODEC )
118 set_shortname( "Daala" )
119 set_description( N_("Daala video decoder") )
120 set_capability( "decoder", 100 )
121 set_callbacks( OpenDecoder, CloseDecoder )
122 add_shortcut( "daala" )
123 add_submodule ()
124 set_description( N_("Daala video packetizer") )
125 set_capability( "packetizer", 100 )
126 set_callbacks( OpenPacketizer, CloseDecoder )
127 add_shortcut( "daala" )
129 #ifdef ENABLE_SOUT
130 add_submodule ()
131 set_description( N_("Daala video encoder") )
132 set_capability( "encoder", 150 )
133 set_callbacks( OpenEncoder, CloseEncoder )
134 add_shortcut( "daala" )
136 # define ENC_CFG_PREFIX "sout-daala-"
137 add_integer_with_range( ENC_CFG_PREFIX "quality", 30, 0, 511,
138 ENC_QUALITY_TEXT, ENC_QUALITY_LONGTEXT, false )
139 add_integer_with_range( ENC_CFG_PREFIX "keyint", 256, 1, 1000,
140 ENC_KEYINT_TEXT, ENC_KEYINT_LONGTEXT, false )
142 # define ENC_CHROMAFMT_TEXT N_("Chroma format")
143 # define ENC_CHROMAFMT_LONGTEXT N_("Picking chroma format will force a " \
144 "conversion of the video into that format")
146 add_string( ENC_CFG_PREFIX "chroma-fmt", "420", ENC_CHROMAFMT_TEXT,
147 ENC_CHROMAFMT_LONGTEXT, false )
148 change_string_list( enc_chromafmt_list, enc_chromafmt_list_text )
149 vlc_module_end ()
151 static const char *const ppsz_enc_options[] = {
152 "quality", "keyint", "chroma-fmt", NULL
154 #endif
156 /*****************************************************************************
157 * OpenDecoder: probe the decoder and return score
158 *****************************************************************************/
159 static int OpenDecoder( vlc_object_t *p_this )
161 decoder_t *p_dec = (decoder_t*)p_this;
162 decoder_sys_t *p_sys;
164 if( p_dec->fmt_in.i_codec != VLC_CODEC_DAALA )
166 return VLC_EGENERIC;
169 /* Allocate the memory needed to store the decoder's structure */
170 p_sys = malloc(sizeof(*p_sys));
171 if( p_sys == NULL )
172 return VLC_ENOMEM;
174 p_dec->p_sys = p_sys;
175 p_dec->p_sys->b_packetizer = false;
176 p_sys->b_has_headers = false;
177 p_sys->i_pts = VLC_TS_INVALID;
178 p_sys->b_decoded_first_keyframe = false;
179 p_sys->dcx = NULL;
181 /* Set output properties */
182 p_dec->fmt_out.i_cat = VIDEO_ES;
183 p_dec->fmt_out.i_codec = VLC_CODEC_I420;
185 /* Set callbacks */
186 p_dec->pf_decode_video = (picture_t *(*)(decoder_t *, block_t **))
187 DecodeBlock;
188 p_dec->pf_packetize = (block_t *(*)(decoder_t *, block_t **))
189 DecodeBlock;
191 /* Init supporting Daala structures needed in header parsing */
192 daala_comment_init( &p_sys->dc );
193 daala_info_init( &p_sys->di );
195 return VLC_SUCCESS;
198 static int OpenPacketizer( vlc_object_t *p_this )
200 decoder_t *p_dec = (decoder_t*)p_this;
202 int i_ret = OpenDecoder( p_this );
204 if( i_ret == VLC_SUCCESS )
206 p_dec->p_sys->b_packetizer = true;
207 p_dec->fmt_out.i_codec = VLC_CODEC_DAALA;
210 return i_ret;
213 /****************************************************************************
214 * DecodeBlock: the whole thing
215 ****************************************************************************
216 * This function must be fed with Daala packets.
217 ****************************************************************************/
218 static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
220 decoder_sys_t *p_sys = p_dec->p_sys;
221 block_t *p_block;
222 daala_packet dpacket;
224 if( !pp_block || !*pp_block ) return NULL;
226 p_block = *pp_block;
228 /* Block to Daala packet */
229 dpacket.packet = p_block->p_buffer;
230 dpacket.bytes = p_block->i_buffer;
231 dpacket.granulepos = p_block->i_dts;
232 dpacket.b_o_s = 0;
233 dpacket.e_o_s = 0;
234 dpacket.packetno = 0;
236 /* Check for headers */
237 if( !p_sys->b_has_headers )
239 if( ProcessHeaders( p_dec ) )
241 block_Release( p_block );
242 return NULL;
244 p_sys->b_has_headers = true;
247 /* If we haven't seen a single keyframe yet, set to preroll,
248 * otherwise we'll get display artifacts. (This is impossible
249 * in the general case, but can happen if e.g. we play a network stream
250 * using a timed URL, such that the server doesn't start the video with a
251 * keyframe). */
252 if( !p_sys->b_decoded_first_keyframe )
253 p_block->i_flags |= BLOCK_FLAG_PREROLL; /* Wait until we've decoded the first keyframe */
255 return ProcessPacket( p_dec, &dpacket, pp_block );
258 /*****************************************************************************
259 * ProcessHeaders: process Daala headers.
260 *****************************************************************************/
261 static int ProcessHeaders( decoder_t *p_dec )
263 int ret = VLC_SUCCESS;
264 decoder_sys_t *p_sys = p_dec->p_sys;
265 daala_packet dpacket;
266 daala_setup_info *ds = NULL; /* daala setup information */
268 unsigned pi_size[XIPH_MAX_HEADER_COUNT];
269 void *pp_data[XIPH_MAX_HEADER_COUNT];
270 unsigned i_count;
271 if( xiph_SplitHeaders( pi_size, pp_data, &i_count,
272 p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) )
273 return VLC_EGENERIC;
274 if( i_count < 3 )
275 return VLC_EGENERIC;
277 dpacket.granulepos = -1;
278 dpacket.e_o_s = 0;
279 dpacket.packetno = 0;
281 /* Take care of the initial info header */
282 dpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
283 dpacket.bytes = pi_size[0];
284 dpacket.packet = pp_data[0];
285 if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &dpacket ) < 0 )
287 msg_Err( p_dec, "this bitstream does not contain Daala video data" );
288 ret = VLC_EGENERIC;
289 goto cleanup;
292 /* Set output properties */
293 if( !p_sys->b_packetizer )
295 if( p_sys->di.plane_info[0].xdec == 0 && p_sys->di.plane_info[0].ydec == 0 &&
296 p_sys->di.plane_info[1].xdec == 1 && p_sys->di.plane_info[1].ydec == 1 &&
297 p_sys->di.plane_info[2].xdec == 1 && p_sys->di.plane_info[2].ydec == 1 )
299 p_dec->fmt_out.i_codec = VLC_CODEC_I420;
301 else if( p_sys->di.plane_info[0].xdec == 0 && p_sys->di.plane_info[0].ydec == 0 &&
302 p_sys->di.plane_info[1].xdec == 0 && p_sys->di.plane_info[1].ydec == 0 &&
303 p_sys->di.plane_info[2].xdec == 0 && p_sys->di.plane_info[2].ydec == 0 )
305 p_dec->fmt_out.i_codec = VLC_CODEC_I444;
307 else
309 msg_Err( p_dec, "unknown chroma in daala sample" );
313 p_dec->fmt_out.video.i_width = p_sys->di.pic_width;
314 p_dec->fmt_out.video.i_height = p_sys->di.pic_height;
315 if( p_sys->di.pic_width && p_sys->di.pic_height )
317 p_dec->fmt_out.video.i_visible_width = p_sys->di.pic_width;
318 p_dec->fmt_out.video.i_visible_height = p_sys->di.pic_height;
321 if( p_sys->di.pixel_aspect_denominator && p_sys->di.pixel_aspect_numerator )
323 p_dec->fmt_out.video.i_sar_num = p_sys->di.pixel_aspect_numerator;
324 p_dec->fmt_out.video.i_sar_den = p_sys->di.pixel_aspect_denominator;
326 else
328 p_dec->fmt_out.video.i_sar_num = 1;
329 p_dec->fmt_out.video.i_sar_den = 1;
332 if( p_sys->di.timebase_numerator > 0 && p_sys->di.timebase_denominator > 0 )
334 p_dec->fmt_out.video.i_frame_rate = p_sys->di.timebase_numerator;
335 p_dec->fmt_out.video.i_frame_rate_base = p_sys->di.timebase_denominator;
338 msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content ",
339 p_sys->di.pic_width, p_sys->di.pic_height,
340 (double)p_sys->di.timebase_numerator/p_sys->di.timebase_denominator );
342 /* The next packet in order is the comments header */
343 dpacket.b_o_s = 0;
344 dpacket.bytes = pi_size[1];
345 dpacket.packet = pp_data[1];
347 if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &dpacket ) < 0 )
349 msg_Err( p_dec, "Daala comment header is corrupted" );
350 ret = VLC_EGENERIC;
351 goto cleanup;
354 ParseDaalaComments( p_dec );
356 /* The next packet in order is the setup header
357 * We need to watch out that this packet is not missing as a
358 * missing or corrupted header is fatal. */
359 dpacket.b_o_s = 0;
360 dpacket.bytes = pi_size[2];
361 dpacket.packet = pp_data[2];
362 if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &dpacket ) < 0 )
364 msg_Err( p_dec, "Daala setup header is corrupted" );
365 ret = VLC_EGENERIC;
366 goto cleanup;
369 if( !p_sys->b_packetizer )
371 /* We have all the headers, initialize decoder */
372 if ( ( p_sys->dcx = daala_decode_create( &p_sys->di, ds ) ) == NULL )
374 msg_Err( p_dec, "Could not allocate Daala decoder" );
375 ret = VLC_EGENERIC;
376 goto cleanup;
379 else
381 void* p_extra = realloc( p_dec->fmt_out.p_extra,
382 p_dec->fmt_in.i_extra );
383 if( unlikely( p_extra == NULL ) )
385 ret = VLC_ENOMEM;
386 goto cleanup;
388 p_dec->fmt_out.p_extra = p_extra;
389 p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
390 memcpy( p_dec->fmt_out.p_extra,
391 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
394 cleanup:
395 /* Clean up the decoder setup info... we're done with it */
396 daala_setup_free( ds );
398 return ret;
401 /*****************************************************************************
402 * ProcessPacket: processes a daala packet.
403 *****************************************************************************/
404 static void *ProcessPacket( decoder_t *p_dec, daala_packet *p_dpacket,
405 block_t **pp_block )
407 decoder_sys_t *p_sys = p_dec->p_sys;
408 block_t *p_block = *pp_block;
409 void *p_buf;
411 if( ( p_block->i_flags&(BLOCK_FLAG_CORRUPTED) ) != 0 )
413 /* Don't send the the first packet after a discontinuity to
414 * daala_decode, otherwise we get purple/green display artifacts
415 * appearing in the video output */
416 block_Release(p_block);
417 return NULL;
420 /* Date management */
421 if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts )
423 p_sys->i_pts = p_block->i_pts;
426 *pp_block = NULL; /* To avoid being fed the same packet again */
428 if( p_sys->b_packetizer )
430 /* Date management */
431 p_block->i_dts = p_block->i_pts = p_sys->i_pts;
433 p_block->i_length = p_sys->i_pts - p_block->i_pts;
435 p_buf = p_block;
437 else
439 p_buf = DecodePacket( p_dec, p_dpacket );
440 block_Release( p_block );
443 /* Date management */
444 p_sys->i_pts += ( CLOCK_FREQ * p_sys->di.timebase_denominator /
445 p_sys->di.timebase_numerator ); /* 1 frame per packet */
447 return p_buf;
450 /*****************************************************************************
451 * DecodePacket: decodes a Daala packet.
452 *****************************************************************************/
453 static picture_t *DecodePacket( decoder_t *p_dec, daala_packet *p_dpacket )
455 decoder_sys_t *p_sys = p_dec->p_sys;
456 picture_t *p_pic;
457 daala_image ycbcr;
459 if (daala_decode_packet_in( p_sys->dcx, p_dpacket ) < 0)
460 return NULL; /* bad packet */
462 if (!daala_decode_img_out( p_sys->dcx, &ycbcr ))
463 return NULL;
465 /* Check for keyframe */
466 if( daala_packet_iskeyframe( p_dpacket ) )
467 p_sys->b_decoded_first_keyframe = true;
469 /* Get a new picture */
470 p_pic = decoder_NewPicture( p_dec );
471 if( !p_pic ) return NULL;
473 daala_CopyPicture( p_pic, &ycbcr );
475 p_pic->date = p_sys->i_pts;
477 return p_pic;
480 /*****************************************************************************
481 * ParseDaalaComments:
482 *****************************************************************************/
483 static void ParseDaalaComments( decoder_t *p_dec )
485 char *psz_name, *psz_value, *psz_comment;
486 /* Regarding the daala_comment structure: */
488 /* The metadata is stored as a series of (tag, value) pairs, in
489 length-encoded string vectors. The first occurrence of the '='
490 character delimits the tag and value. A particular tag may
491 occur more than once, and order is significant. The character
492 set encoding for the strings is always UTF-8, but the tag names
493 are limited to ASCII, and treated as case-insensitive. See the
494 Theora specification, Section 6.3.3 for details. */
496 /* In filling in this structure, daala_decode_header_in() will
497 null-terminate the user_comment strings for safety. However,
498 the bitstream format itself treats them as 8-bit clean vectors,
499 possibly containing null characters, and so the length array
500 should be treated as their authoritative length. */
501 for ( int i = 0; i < p_dec->p_sys->dc.comments; i++ )
503 int clen = p_dec->p_sys->dc.comment_lengths[i];
504 if ( clen <= 0 || clen >= INT_MAX ) { continue; }
505 psz_comment = malloc( clen + 1 );
506 if( !psz_comment )
507 break;
508 memcpy( (void*)psz_comment, (void*)p_dec->p_sys->dc.user_comments[i], clen + 1 );
509 psz_comment[clen] = '\0';
511 psz_name = psz_comment;
512 psz_value = strchr( psz_comment, '=' );
513 if( psz_value )
515 *psz_value = '\0';
516 psz_value++;
518 if( !p_dec->p_description )
519 p_dec->p_description = vlc_meta_New();
520 /* TODO: Since psz_value can contain NULLs see if there is an
521 * instance where we need to preserve the full length of this string */
522 if( p_dec->p_description )
523 vlc_meta_AddExtra( p_dec->p_description, psz_name, psz_value );
525 free( psz_comment );
529 /*****************************************************************************
530 * CloseDecoder: daala decoder destruction
531 *****************************************************************************/
532 static void CloseDecoder( vlc_object_t *p_this )
534 decoder_t *p_dec = (decoder_t *)p_this;
535 decoder_sys_t *p_sys = p_dec->p_sys;
537 daala_info_clear(&p_sys->di);
538 daala_comment_clear(&p_sys->dc);
539 daala_decode_free(p_sys->dcx);
540 free( p_sys );
543 /*****************************************************************************
544 * daala_CopyPicture: copy a picture from daala internal buffers to a
545 * picture_t structure.
546 *****************************************************************************/
547 static void daala_CopyPicture( picture_t *p_pic,
548 daala_image *ycbcr )
550 const int i_planes = p_pic->i_planes < 3 ? p_pic->i_planes : 3;
551 for( int i_plane = 0; i_plane < i_planes; i_plane++ )
553 const int i_total_lines = __MIN(p_pic->p[i_plane].i_lines,
554 ycbcr->height >> ycbcr->planes[i_plane].ydec);
555 uint8_t *p_dst = p_pic->p[i_plane].p_pixels;
556 uint8_t *p_src = ycbcr->planes[i_plane].data;
557 const int i_dst_stride = p_pic->p[i_plane].i_pitch;
558 const int i_src_stride = ycbcr->planes[i_plane].ystride;
559 for( int i_line = 0; i_line < i_total_lines; i_line++ )
561 memcpy( p_dst, p_src, i_src_stride );
562 p_src += i_src_stride;
563 p_dst += i_dst_stride;
568 #ifdef ENABLE_SOUT
569 struct encoder_sys_t
571 daala_info di; /* daala bitstream settings */
572 daala_comment dc; /* daala comment header */
573 daala_enc_ctx *dcx; /* daala context */
576 static int OpenEncoder( vlc_object_t *p_this )
578 encoder_t *p_enc = (encoder_t *)p_this;
579 encoder_sys_t *p_sys;
580 daala_packet header;
581 int status;
583 if( p_enc->fmt_out.i_codec != VLC_CODEC_DAALA &&
584 !p_enc->b_force )
586 return VLC_EGENERIC;
589 /* Allocate the memory needed to store the encoder's structure */
590 p_sys = malloc( sizeof( encoder_sys_t ) );
591 if( !p_sys )
592 return VLC_ENOMEM;
593 p_enc->p_sys = p_sys;
595 p_enc->pf_encode_video = Encode;
596 p_enc->fmt_in.i_codec = VLC_CODEC_I420;
597 p_enc->fmt_out.i_codec = VLC_CODEC_DAALA;
599 config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
601 char *psz_tmp = var_GetString( p_enc, ENC_CFG_PREFIX "chroma-fmt" );
602 uint32_t i_codec;
603 if( !psz_tmp ) {
604 free(p_sys);
605 return VLC_ENOMEM;
606 } else {
607 if( !strcmp( psz_tmp, "420" ) ) {
608 i_codec = VLC_CODEC_I420;
610 else if( !strcmp( psz_tmp, "444" ) ) {
611 i_codec = VLC_CODEC_I444;
613 else {
614 msg_Err( p_enc, "Invalid chroma format: %s", psz_tmp );
615 free( psz_tmp );
616 free( p_sys );
617 return VLC_EGENERIC;
619 free( psz_tmp );
620 p_enc->fmt_in.i_codec = i_codec;
621 /* update bits_per_pixel */
622 video_format_Setup(&p_enc->fmt_in.video, i_codec,
623 p_enc->fmt_in.video.i_width,
624 p_enc->fmt_in.video.i_height,
625 p_enc->fmt_in.video.i_visible_width,
626 p_enc->fmt_in.video.i_visible_height,
627 p_enc->fmt_in.video.i_sar_num,
628 p_enc->fmt_in.video.i_sar_den);
631 daala_info_init( &p_sys->di );
633 p_sys->di.pic_width = p_enc->fmt_in.video.i_visible_width;
634 p_sys->di.pic_height = p_enc->fmt_in.video.i_visible_height;
636 p_sys->di.nplanes = 3;
637 for (int i = 0; i < p_sys->di.nplanes; i++)
639 p_sys->di.plane_info[i].xdec = i > 0 && i_codec != VLC_CODEC_I444;
640 p_sys->di.plane_info[i].ydec = i_codec == VLC_CODEC_I420 ?
641 p_sys->di.plane_info[i].xdec : 0;
643 p_sys->di.frame_duration = 1;
645 if( !p_enc->fmt_in.video.i_frame_rate ||
646 !p_enc->fmt_in.video.i_frame_rate_base )
648 p_sys->di.timebase_numerator = 25;
649 p_sys->di.timebase_denominator = 1;
651 else
653 p_sys->di.timebase_numerator = p_enc->fmt_in.video.i_frame_rate;
654 p_sys->di.timebase_denominator = p_enc->fmt_in.video.i_frame_rate_base;
657 if( p_enc->fmt_in.video.i_sar_num > 0 && p_enc->fmt_in.video.i_sar_den > 0 )
659 unsigned i_dst_num, i_dst_den;
660 vlc_ureduce( &i_dst_num, &i_dst_den,
661 p_enc->fmt_in.video.i_sar_num,
662 p_enc->fmt_in.video.i_sar_den, 0 );
663 p_sys->di.pixel_aspect_numerator = i_dst_num;
664 p_sys->di.pixel_aspect_denominator = i_dst_den;
666 else
668 p_sys->di.pixel_aspect_numerator = 4;
669 p_sys->di.pixel_aspect_denominator = 3;
672 p_sys->di.keyframe_rate = var_GetInteger( p_enc, ENC_CFG_PREFIX "keyint" );
674 daala_enc_ctx *dcx;
675 p_sys->dcx = dcx = daala_encode_create( &p_sys->di );
676 if( !dcx )
678 free( p_sys );
679 return VLC_ENOMEM;
682 daala_comment_init( &p_sys->dc );
684 int i_quality = var_GetInteger( p_enc, ENC_CFG_PREFIX "quality" );
685 daala_encode_ctl( dcx, OD_SET_QUANT, &i_quality, sizeof(i_quality) );
687 /* Create and store headers */
688 while( ( status = daala_encode_flush_header( dcx, &p_sys->dc, &header ) ) )
690 if ( status < 0 )
692 CloseEncoder( p_this );
693 return VLC_EGENERIC;
695 if( xiph_AppendHeaders( &p_enc->fmt_out.i_extra,
696 &p_enc->fmt_out.p_extra, header.bytes,
697 header.packet ) )
699 p_enc->fmt_out.i_extra = 0;
700 p_enc->fmt_out.p_extra = NULL;
703 return VLC_SUCCESS;
706 static block_t *Encode( encoder_t *p_enc, picture_t *p_pict )
708 encoder_sys_t *p_sys = p_enc->p_sys;
709 daala_packet dpacket;
710 block_t *p_block;
711 daala_image img;
713 if( !p_pict ) return NULL;
715 const int i_width = p_sys->di.pic_width;
716 const int i_height = p_sys->di.pic_height;
718 /* Sanity check */
719 if( p_pict->p[0].i_pitch < i_width ||
720 p_pict->p[0].i_lines < i_height )
722 msg_Err( p_enc, "frame is smaller than encoding size"
723 "(%ix%i->%ix%i) -> dropping frame",
724 p_pict->p[0].i_pitch, p_pict->p[0].i_lines,
725 i_width, i_height );
726 return NULL;
729 /* Daala is a one-frame-in, one-frame-out system. Submit a frame
730 * for compression and pull out the packet. */
732 img.nplanes = p_sys->di.nplanes;
733 img.width = i_width;
734 img.height = i_height;
735 for( int i = 0; i < img.nplanes; i++ )
737 img.planes[i].data = p_pict->p[i].p_pixels;
738 img.planes[i].xdec = p_sys->di.plane_info[i].xdec;
739 img.planes[i].ydec = p_sys->di.plane_info[i].ydec;
740 img.planes[i].xstride = 1;
741 img.planes[i].ystride = p_pict->p[i].i_pitch;
742 img.planes[i].bitdepth = 8; /*FIXME: support higher bit depths*/
745 if( daala_encode_img_in( p_sys->dcx, &img, 0 ) < 0 )
747 msg_Warn( p_enc, "failed encoding a frame" );
748 return NULL;
751 daala_encode_packet_out( p_sys->dcx, 0, &dpacket );
753 /* Daala packet to block */
754 p_block = block_Alloc( dpacket.bytes );
755 memcpy( p_block->p_buffer, dpacket.packet, dpacket.bytes );
756 p_block->i_dts = p_block->i_pts = p_pict->date;
758 if( daala_packet_iskeyframe( &dpacket ) )
759 p_block->i_flags |= BLOCK_FLAG_TYPE_I;
761 return p_block;
764 static void CloseEncoder( vlc_object_t *p_this )
766 encoder_t *p_enc = (encoder_t *)p_this;
767 encoder_sys_t *p_sys = p_enc->p_sys;
769 daala_info_clear(&p_sys->di);
770 daala_comment_clear(&p_sys->dc);
771 daala_encode_free(p_sys->dcx);
772 free( p_sys );
774 #endif