+
+static uint32_t dirac_uint( bs_t *p_bs )
+{
+ uint32_t u_count = 0, u_value = 0;
+
+ while( !bs_eof( p_bs ) && !bs_read( p_bs, 1 ) )
+ {
+ u_count++;
+ u_value <<= 1;
+ u_value |= bs_read( p_bs, 1 );
+ }
+
+ return (1<<u_count) - 1 + u_value;
+}
+
+static int dirac_bool( bs_t *p_bs )
+{
+ return bs_read( p_bs, 1 );
+}
+
+static bool Ogg_ReadDiracHeader( logical_stream_t *p_stream,
+ ogg_packet *p_oggpacket )
+{
+ static const struct {
+ uint32_t u_n /* numerator */, u_d /* denominator */;
+ } p_dirac_frate_tbl[] = { /* table 10.3 */
+ {1,1}, /* this first value is never used */
+ {24000,1001}, {24,1}, {25,1}, {30000,1001}, {30,1},
+ {50,1}, {60000,1001}, {60,1}, {15000,1001}, {25,2},
+ };
+ static const size_t u_dirac_frate_tbl = sizeof(p_dirac_frate_tbl)/sizeof(*p_dirac_frate_tbl);
+
+ static const uint32_t pu_dirac_vidfmt_frate[] = { /* table C.1 */
+ 1, 9, 10, 9, 10, 9, 10, 4, 3, 7, 6, 4, 3, 7, 6, 2, 2, 7, 6, 7, 6,
+ };
+ static const size_t u_dirac_vidfmt_frate = sizeof(pu_dirac_vidfmt_frate)/sizeof(*pu_dirac_vidfmt_frate);
+
+ bs_t bs;
+
+ p_stream->i_granule_shift = 22; /* not 32 */
+
+ /* Backing up stream headers is not required -- seqhdrs are repeated
+ * thoughout the stream at suitable decoding start points */
+ p_stream->b_force_backup = 0;
+
+ /* read in useful bits from sequence header */
+ bs_init( &bs, p_oggpacket->packet, p_oggpacket->bytes );
+ bs_skip( &bs, 13*8); /* parse_info_header */
+ dirac_uint( &bs ); /* major_version */
+ dirac_uint( &bs ); /* minor_version */
+ dirac_uint( &bs ); /* profile */
+ dirac_uint( &bs ); /* level */
+
+ uint32_t u_video_format = dirac_uint( &bs ); /* index */
+ if( u_video_format >= u_dirac_vidfmt_frate )
+ {
+ /* don't know how to parse this ogg dirac stream */
+ return false;
+ }
+
+ if( dirac_bool( &bs ) )
+ {
+ dirac_uint( &bs ); /* frame_width */
+ dirac_uint( &bs ); /* frame_height */
+ }
+
+ if( dirac_bool( &bs ) )
+ {
+ dirac_uint( &bs ); /* chroma_format */
+ }
+
+ if( dirac_bool( &bs ) )
+ {
+ dirac_uint( &bs ); /* scan_format */
+ }
+
+ uint32_t u_n = p_dirac_frate_tbl[pu_dirac_vidfmt_frate[u_video_format]].u_n;
+ uint32_t u_d = p_dirac_frate_tbl[pu_dirac_vidfmt_frate[u_video_format]].u_d;
+ if( dirac_bool( &bs ) )
+ {
+ uint32_t u_frame_rate_index = dirac_uint( &bs );
+ if( u_frame_rate_index >= u_dirac_frate_tbl )
+ {
+ /* something is wrong with this stream */
+ return false;
+ }
+ u_n = p_dirac_frate_tbl[u_frame_rate_index].u_n;
+ u_d = p_dirac_frate_tbl[u_frame_rate_index].u_d;
+ if( u_frame_rate_index == 0 )
+ {
+ u_n = dirac_uint( &bs ); /* frame_rate_numerator */
+ u_d = dirac_uint( &bs ); /* frame_rate_denominator */
+ }
+ }
+ p_stream->f_rate = (float) u_n / u_d;
+
+ /* probably is an ogg dirac es */
+ p_stream->fmt.i_cat = VIDEO_ES;
+ p_stream->fmt.i_codec = VLC_CODEC_DIRAC;
+
+ return true;
+}