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