/***************************************************************************** * ProcessHeaders: process Opus headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { ogg_packet oggpacket; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; if( xiph_SplitHeaders( pi_size, pp_data, &i_count, p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; if( i_count < 2 ) return VLC_EGENERIC;; oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial Opus header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = pp_data[0]; int ret = ProcessInitialHeader( p_dec, &oggpacket ); if (ret != VLC_SUCCESS) msg_Err( p_dec, "initial Opus header is corrupted" ); return ret; }
/***************************************************************************** * ProcessHeaders: process Opus headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { ogg_packet oggpacket; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; int i_extra = p_dec->fmt_in.i_extra; uint8_t *p_extra = p_dec->fmt_in.p_extra; /* If we have no header (e.g. from RTP), make one. */ bool b_dummy_header = false; if( !i_extra ) { OpusHeader header; opus_prepare_header( p_dec->fmt_in.audio.i_channels, p_dec->fmt_in.audio.i_rate, &header ); if( opus_write_header( &p_extra, &i_extra, &header, opus_get_version_string() ) ) return VLC_ENOMEM; b_dummy_header = true; } if( xiph_SplitHeaders( pi_size, pp_data, &i_count, i_extra, p_extra ) ) { if( b_dummy_header ) free( p_extra ); return VLC_EGENERIC; } if( i_count < 2 ) { if( b_dummy_header ) free( p_extra ); return VLC_EGENERIC; } oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial Opus header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = pp_data[0]; int ret = ProcessInitialHeader( p_dec, &oggpacket ); if (ret != VLC_SUCCESS) msg_Err( p_dec, "initial Opus header is corrupted" ); if( b_dummy_header ) free( p_extra ); return ret; }
/***************************************************************************** * ProcessHeaders: process Speex headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; ogg_packet oggpacket; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; if( xiph_SplitHeaders( pi_size, pp_data, &i_count, p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; if( i_count < 2 ) goto error; oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial Vorbis header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = (unsigned char *)pp_data[0]; // sunqueen modify if( ProcessInitialHeader( p_dec, &oggpacket ) != VLC_SUCCESS ) { msg_Err( p_dec, "initial Speex header is corrupted" ); goto error; } /* The next packet in order is the comments header */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[1]; oggpacket.packet = (unsigned char *)pp_data[1]; // sunqueen modify ParseSpeexComments( p_dec, &oggpacket ); if( p_sys->b_packetizer ) { p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } for( unsigned i = 0; i < i_count; i++ ) free( pp_data[i] ); return VLC_SUCCESS; error: for( unsigned i = 0; i < i_count; i++ ) free( pp_data[i] ); return VLC_EGENERIC; }
/***************************************************************************** * ProcessHeaders: process Speex headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; ogg_packet oggpacket; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; if( xiph_SplitHeaders( pi_size, pp_data, &i_count, p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; if( i_count < 2 ) return VLC_EGENERIC;; oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial Vorbis header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = pp_data[0]; if( ProcessInitialHeader( p_dec, &oggpacket ) != VLC_SUCCESS ) { msg_Err( p_dec, "initial Speex header is corrupted" ); return VLC_EGENERIC;; } /* The next packet in order is the comments header */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[1]; oggpacket.packet = pp_data[1]; ParseSpeexComments( p_dec, &oggpacket ); if( p_sys->b_packetizer ) { void* p_extra = realloc( p_dec->fmt_out.p_extra, p_dec->fmt_in.i_extra ); if( unlikely( p_extra == NULL ) ) { return VLC_ENOMEM; } p_dec->fmt_out.p_extra = p_extra; p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } return VLC_SUCCESS; }
/***************************************************************************** * ProcessHeaders: process Daala headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { int ret = VLC_SUCCESS; decoder_sys_t *p_sys = p_dec->p_sys; ogg_packet oggpacket; daala_setup_info *ds = NULL; /* daala setup information */ unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; if( xiph_SplitHeaders( pi_size, pp_data, &i_count, p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; if( i_count < 3 ) return VLC_EGENERIC; oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial info header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = pp_data[0]; if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &oggpacket ) < 0 ) { msg_Err( p_dec, "this bitstream does not contain Daala video data" ); ret = VLC_EGENERIC; goto cleanup; } /* Set output properties */ if( !p_sys->b_packetizer ) { if( p_sys->di.plane_info[0].xdec == 0 && p_sys->di.plane_info[0].ydec == 0 && p_sys->di.plane_info[1].xdec == 1 && p_sys->di.plane_info[1].ydec == 1 && p_sys->di.plane_info[2].xdec == 1 && p_sys->di.plane_info[2].ydec == 1 ) { p_dec->fmt_out.i_codec = VLC_CODEC_I420; } else if( p_sys->di.plane_info[0].xdec == 0 && p_sys->di.plane_info[0].ydec == 0 && p_sys->di.plane_info[1].xdec == 0 && p_sys->di.plane_info[1].ydec == 0 && p_sys->di.plane_info[2].xdec == 0 && p_sys->di.plane_info[2].ydec == 0 ) { p_dec->fmt_out.i_codec = VLC_CODEC_I444; } else { msg_Err( p_dec, "unknown chroma in daala sample" ); } } p_dec->fmt_out.video.i_width = p_sys->di.pic_width; p_dec->fmt_out.video.i_height = p_sys->di.pic_height; if( p_sys->di.pic_width && p_sys->di.pic_height ) { p_dec->fmt_out.video.i_visible_width = p_sys->di.pic_width; p_dec->fmt_out.video.i_visible_height = p_sys->di.pic_height; } if( p_sys->di.pixel_aspect_denominator && p_sys->di.pixel_aspect_numerator ) { p_dec->fmt_out.video.i_sar_num = p_sys->di.pixel_aspect_numerator; p_dec->fmt_out.video.i_sar_den = p_sys->di.pixel_aspect_denominator; } else { p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; } if( p_sys->di.timebase_numerator > 0 && p_sys->di.timebase_denominator > 0 ) { p_dec->fmt_out.video.i_frame_rate = p_sys->di.timebase_numerator; p_dec->fmt_out.video.i_frame_rate_base = p_sys->di.timebase_denominator; } msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content ", p_sys->di.pic_width, p_sys->di.pic_height, (double)p_sys->di.timebase_numerator/p_sys->di.timebase_denominator ); /* The next packet in order is the comments header */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[1]; oggpacket.packet = pp_data[1]; if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &oggpacket ) < 0 ) { msg_Err( p_dec, "Daala comment header is corrupted" ); ret = VLC_EGENERIC; goto cleanup; } ParseDaalaComments( p_dec ); /* The next packet in order is the setup header * We need to watch out that this packet is not missing as a * missing or corrupted header is fatal. */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[2]; oggpacket.packet = pp_data[2]; if( daala_decode_header_in( &p_sys->di, &p_sys->dc, &ds, &oggpacket ) < 0 ) { msg_Err( p_dec, "Daala setup header is corrupted" ); ret = VLC_EGENERIC; goto cleanup; } if( !p_sys->b_packetizer ) { /* We have all the headers, initialize decoder */ if ( ( p_sys->dcx = daala_decode_alloc( &p_sys->di, ds ) ) == NULL ) { msg_Err( p_dec, "Could not allocate Daala decoder" ); ret = VLC_EGENERIC; goto cleanup; } } else { p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } cleanup: /* Clean up the decoder setup info... we're done with it */ daala_setup_free( ds ); return ret; }
/***************************************************************************** * ProcessHeaders: process Vorbis headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; ogg_packet oggpacket; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; if( xiph_SplitHeaders( pi_size, pp_data, &i_count, p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; if( i_count < 3 ) return VLC_EGENERIC; oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial Vorbis header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = pp_data[0]; if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 ) { msg_Err( p_dec, "this bitstream does not contain Vorbis audio data"); return VLC_EGENERIC; } /* Setup the format */ p_dec->fmt_out.audio.i_rate = p_sys->vi.rate; p_dec->fmt_out.audio.i_channels = p_sys->vi.channels; if( p_dec->fmt_out.audio.i_channels >= ARRAY_SIZE(pi_channels_maps) ) { msg_Err( p_dec, "invalid number of channels (1-%zu): %i", ARRAY_SIZE(pi_channels_maps), p_dec->fmt_out.audio.i_channels ); return VLC_EGENERIC; } p_dec->fmt_out.audio.i_physical_channels = p_dec->fmt_out.audio.i_original_channels = pi_channels_maps[p_sys->vi.channels]; p_dec->fmt_out.i_bitrate = __MAX( 0, (int32_t) p_sys->vi.bitrate_nominal ); date_Init( &p_sys->end_date, p_sys->vi.rate, 1 ); msg_Dbg( p_dec, "channels:%d samplerate:%ld bitrate:%ud", p_sys->vi.channels, p_sys->vi.rate, p_dec->fmt_out.i_bitrate ); /* The next packet in order is the comments header */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[1]; oggpacket.packet = pp_data[1]; if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 ) { msg_Err( p_dec, "2nd Vorbis header is corrupted" ); return VLC_EGENERIC; } ParseVorbisComments( p_dec ); /* The next packet in order is the codebooks header * We need to watch out that this packet is not missing as a * missing or corrupted header is fatal. */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[2]; oggpacket.packet = pp_data[2]; if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 ) { msg_Err( p_dec, "3rd Vorbis header is corrupted" ); return VLC_EGENERIC; } if( !p_sys->b_packetizer ) { /* Initialize the Vorbis packet->PCM decoder */ vorbis_synthesis_init( &p_sys->vd, &p_sys->vi ); vorbis_block_init( &p_sys->vd, &p_sys->vb ); } else { p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } ConfigureChannelOrder(p_sys->pi_chan_table, p_sys->vi.channels, p_dec->fmt_out.audio.i_physical_channels, true); return VLC_SUCCESS; }
/***************************************************************************** * ProcessHeaders: process Theora headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; ogg_packet oggpacket; th_setup_info *ts = NULL; /* theora setup information */ int i_max_pp, i_pp; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; if( xiph_SplitHeaders( pi_size, pp_data, &i_count, p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; if( i_count < 3 ) goto error; oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial Vorbis header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = pp_data[0]; if( th_decode_headerin( &p_sys->ti, &p_sys->tc, &ts, &oggpacket ) < 0 ) { msg_Err( p_dec, "this bitstream does not contain Theora video data" ); goto error; } /* Set output properties */ if( !p_sys->b_packetizer ) switch( p_sys->ti.pixel_fmt ) { case TH_PF_420: p_dec->fmt_out.i_codec = VLC_CODEC_I420; break; case TH_PF_422: p_dec->fmt_out.i_codec = VLC_CODEC_I422; break; case TH_PF_444: p_dec->fmt_out.i_codec = VLC_CODEC_I444; break; case TH_PF_RSVD: default: msg_Err( p_dec, "unknown chroma in theora sample" ); break; } p_dec->fmt_out.video.i_width = p_sys->ti.frame_width; p_dec->fmt_out.video.i_height = p_sys->ti.frame_height; if( p_sys->ti.pic_width && p_sys->ti.pic_height ) { p_dec->fmt_out.video.i_visible_width = p_sys->ti.pic_width; p_dec->fmt_out.video.i_visible_height = p_sys->ti.pic_height; if( p_sys->ti.pic_x || p_sys->ti.pic_y ) { p_dec->fmt_out.video.i_x_offset = p_sys->ti.pic_x; p_dec->fmt_out.video.i_y_offset = p_sys->ti.pic_y; } } if( p_sys->ti.aspect_denominator && p_sys->ti.aspect_numerator ) { p_dec->fmt_out.video.i_sar_num = p_sys->ti.aspect_numerator; p_dec->fmt_out.video.i_sar_den = p_sys->ti.aspect_denominator; } else { p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; } if( p_sys->ti.fps_numerator > 0 && p_sys->ti.fps_denominator > 0 ) { p_dec->fmt_out.video.i_frame_rate = p_sys->ti.fps_numerator; p_dec->fmt_out.video.i_frame_rate_base = p_sys->ti.fps_denominator; } msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content " "is %dx%d with offset (%d,%d)", p_sys->ti.frame_width, p_sys->ti.frame_height, (double)p_sys->ti.fps_numerator/p_sys->ti.fps_denominator, p_sys->ti.pic_width, p_sys->ti.pic_height, p_sys->ti.pic_x, p_sys->ti.pic_y ); /* Some assertions based on the documentation. These are mandatory restrictions. */ assert( p_sys->ti.frame_height % 16 == 0 && p_sys->ti.frame_height < 1048576 ); assert( p_sys->ti.frame_width % 16 == 0 && p_sys->ti.frame_width < 1048576 ); assert( p_sys->ti.keyframe_granule_shift >= 0 && p_sys->ti.keyframe_granule_shift <= 31 ); assert( p_sys->ti.pic_x <= __MIN( p_sys->ti.frame_width - p_sys->ti.pic_width, 255 ) ); assert( p_sys->ti.pic_y <= p_sys->ti.frame_height - p_sys->ti.pic_height); assert( p_sys->ti.frame_height - p_sys->ti.pic_height - p_sys->ti.pic_y <= 255 ); /* Sanity check that seems necessary for some corrupted files */ if( p_sys->ti.frame_width < p_sys->ti.pic_width || p_sys->ti.frame_height < p_sys->ti.pic_height ) { msg_Warn( p_dec, "trying to correct invalid theora header " "(frame size (%dx%d) is smaller than frame content (%d,%d))", p_sys->ti.frame_width, p_sys->ti.frame_height, p_sys->ti.pic_width, p_sys->ti.pic_height ); if( p_sys->ti.frame_width < p_sys->ti.pic_width ) p_sys->ti.frame_width = p_sys->ti.pic_width; if( p_sys->ti.frame_height < p_sys->ti.pic_height ) p_sys->ti.frame_height = p_sys->ti.pic_height; } /* The next packet in order is the comments header */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[1]; oggpacket.packet = pp_data[1]; if( th_decode_headerin( &p_sys->ti, &p_sys->tc, &ts, &oggpacket ) < 0 ) { msg_Err( p_dec, "2nd Theora header is corrupted" ); goto error; } ParseTheoraComments( p_dec ); /* The next packet in order is the codebooks header * We need to watch out that this packet is not missing as a * missing or corrupted header is fatal. */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[2]; oggpacket.packet = pp_data[2]; if( th_decode_headerin( &p_sys->ti, &p_sys->tc, &ts, &oggpacket ) < 0 ) { msg_Err( p_dec, "3rd Theora header is corrupted" ); goto error; } if( !p_sys->b_packetizer ) { /* We have all the headers, initialize decoder */ if ( ( p_sys->tcx = th_decode_alloc( &p_sys->ti, ts ) ) == NULL ) { msg_Err( p_dec, "Could not allocate Theora decoder" ); goto error; } i_pp = var_InheritInteger( p_dec, DEC_CFG_PREFIX "postproc" ); if ( i_pp >= 0 && !th_decode_ctl( p_sys->tcx, TH_DECCTL_GET_PPLEVEL_MAX, &i_max_pp, sizeof(int) ) ) { i_pp = __MIN( i_pp, i_max_pp ); if ( th_decode_ctl( p_sys->tcx, TH_DECCTL_SET_PPLEVEL, &i_pp, sizeof(int) ) ) msg_Err( p_dec, "Failed to set post processing level to %d", i_pp ); else msg_Dbg( p_dec, "Set post processing level to %d / %d", i_pp, i_max_pp ); } } else { p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } for( unsigned i = 0; i < i_count; i++ ) free( pp_data[i] ); /* Clean up the decoder setup info... we're done with it */ th_setup_free( ts ); return VLC_SUCCESS; error: for( unsigned i = 0; i < i_count; i++ ) free( pp_data[i] ); /* Clean up the decoder setup info... we're done with it */ th_setup_free( ts ); return VLC_EGENERIC; }
/***************************************************************************** * ProcessHeaders: process Kate headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; kate_packet kp; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; if( xiph_SplitHeaders( pi_size, pp_data, &i_count, p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; int i_ret = VLC_SUCCESS; if( i_count < 1 ) { i_ret = VLC_EGENERIC; goto end; } /* Take care of the initial Kate header */ kp.nbytes = pi_size[0]; kp.data = pp_data[0]; i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp ); if( i_ret < 0 ) { msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret ); goto end; } msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d", p_sys->ki.language, p_sys->ki.category, (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator, p_sys->ki.granule_shift); /* parse all remaining header packets */ for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ ) { kp.nbytes = pi_size[i_headeridx]; kp.data = pp_data[i_headeridx]; i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp ); if( i_ret < 0 ) { msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret ); goto end; } /* header 1 is comments */ if( i_headeridx == 1 ) { ParseKateComments( p_dec ); } } #ifdef ENABLE_PACKETIZER if( !p_sys->b_packetizer ) #endif { /* We have all the headers, initialize decoder */ msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" ); i_ret = kate_decode_init( &p_sys->k, &p_sys->ki ); if (i_ret < 0) { msg_Err( p_dec, "Kate failed to initialize for decoding: %d", i_ret ); return VLC_EGENERIC; } p_sys->b_ready = true; } #ifdef ENABLE_PACKETIZER else { p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } #endif end: for( unsigned i = 0; i < i_count; i++ ) free( pp_data[i] ); return i_ret < 0 ? VLC_EGENERIC : VLC_SUCCESS; }
/***************************************************************************** * AddStream *****************************************************************************/ static int AddStream( sout_mux_t *p_mux, sout_input_t *p_input ) { sout_mux_sys_t *p_sys = p_mux->p_sys; const es_format_t *fmt = p_input->p_fmt; unsigned i_codec_id; msg_Dbg( p_mux, "adding input" ); if( !GetFfmpegCodec( fmt->i_cat, fmt->i_codec, &i_codec_id, NULL ) || i_codec_id == AV_CODEC_ID_NONE ) { msg_Dbg( p_mux, "couldn't find codec for fourcc '%4.4s'", (char *)&fmt->i_codec ); return VLC_EGENERIC; } unsigned opus_size[XIPH_MAX_HEADER_COUNT]; void *opus_packet[XIPH_MAX_HEADER_COUNT]; if( fmt->i_codec == VLC_CODEC_OPUS ) { unsigned count; /* Only transmits the first packet (OpusHead) */ if( xiph_SplitHeaders(opus_size, opus_packet, &count, fmt->i_extra, fmt->p_extra ) ) { count = 0; } if (count != 2 || opus_size[0] < 19) { msg_Err(p_mux, "Invalid Opus header"); return VLC_EGENERIC; } } if( fmt->i_cat != VIDEO_ES && fmt->i_cat != AUDIO_ES) { msg_Warn( p_mux, "Unhandled ES category" ); return VLC_EGENERIC; } /* */ p_input->p_sys = malloc( sizeof( int ) ); if( unlikely(p_input->p_sys == NULL) ) return VLC_ENOMEM; *((int *)p_input->p_sys) = p_sys->oc->nb_streams; /* */ AVStream *stream = avformat_new_stream( p_sys->oc, NULL); if( !stream ) { free( p_input->p_sys ); return VLC_EGENERIC; } #if (LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 5, 0)) AVCodecParameters *codecpar = stream->codecpar; #else AVCodecContext *codecpar = stream->codec; #endif unsigned int i_bitrate = fmt->i_bitrate; unsigned int i_frame_rate = fmt->video.i_frame_rate; unsigned int i_frame_rate_base = fmt->video.i_frame_rate_base; switch( fmt->i_cat ) { case AUDIO_ES: codecpar->codec_type = AVMEDIA_TYPE_AUDIO; codecpar->channels = fmt->audio.i_channels; codecpar->sample_rate = fmt->audio.i_rate; stream->time_base = (AVRational){1, codecpar->sample_rate}; if (fmt->i_bitrate == 0) { msg_Warn( p_mux, "Missing audio bitrate, assuming 64k" ); i_bitrate = 64000; } break; case VIDEO_ES: if( !fmt->video.i_frame_rate || !fmt->video.i_frame_rate_base ) { msg_Warn( p_mux, "Missing frame rate, assuming 25fps" ); i_frame_rate = 25; i_frame_rate_base = 1; } else msg_Dbg( p_mux, "Muxing framerate will be %d/%d = %.2f fps", fmt->video.i_frame_rate, fmt->video.i_frame_rate_base, (double)fmt->video.i_frame_rate/(double)fmt->video.i_frame_rate_base ); codecpar->codec_type = AVMEDIA_TYPE_VIDEO; codecpar->width = fmt->video.i_visible_width; codecpar->height = fmt->video.i_visible_height; av_reduce( &codecpar->sample_aspect_ratio.num, &codecpar->sample_aspect_ratio.den, fmt->video.i_sar_num, fmt->video.i_sar_den, 1 << 30 /* something big */ ); msg_Dbg(p_mux, "Muxing aspect ratio will be %d/%d", fmt->video.i_sar_num, fmt->video.i_sar_den); stream->sample_aspect_ratio.den = codecpar->sample_aspect_ratio.den; stream->sample_aspect_ratio.num = codecpar->sample_aspect_ratio.num; stream->time_base.den = i_frame_rate; stream->time_base.num = i_frame_rate_base; if (fmt->i_bitrate == 0) { msg_Warn( p_mux, "Missing video bitrate, assuming 512k" ); i_bitrate = 512000; } else msg_Dbg( p_mux, "Muxing video bitrate will be %d", fmt->i_bitrate ); break; default: vlc_assert_unreachable(); } codecpar->bit_rate = i_bitrate; codecpar->codec_tag = av_codec_get_tag( p_sys->oc->oformat->codec_tag, i_codec_id ); if( !codecpar->codec_tag && i_codec_id == AV_CODEC_ID_MP2 ) { i_codec_id = AV_CODEC_ID_MP3; codecpar->codec_tag = av_codec_get_tag( p_sys->oc->oformat->codec_tag, i_codec_id ); } codecpar->codec_id = i_codec_id; if( fmt->i_extra ) { if( fmt->i_codec == VLC_CODEC_OPUS ) { codecpar->extradata_size = opus_size[0]; codecpar->extradata = av_malloc( opus_size[0] ); memcpy( codecpar->extradata, opus_packet[0], opus_size[0] ); } else { codecpar->extradata_size = fmt->i_extra; codecpar->extradata = av_malloc( fmt->i_extra ); memcpy( codecpar->extradata, fmt->p_extra, fmt->i_extra ); } } return VLC_SUCCESS; }
/***************************************************************************** * ProcessHeaders: process Theora headers. *****************************************************************************/ static int ProcessHeaders( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; ogg_packet oggpacket; unsigned pi_size[XIPH_MAX_HEADER_COUNT]; void *pp_data[XIPH_MAX_HEADER_COUNT]; unsigned i_count; if( xiph_SplitHeaders( pi_size, pp_data, &i_count, p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; if( i_count < 3 ) goto error; oggpacket.granulepos = -1; oggpacket.e_o_s = 0; oggpacket.packetno = 0; /* Take care of the initial Vorbis header */ oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */ oggpacket.bytes = pi_size[0]; oggpacket.packet = pp_data[0]; if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 ) { msg_Err( p_dec, "this bitstream does not contain Theora video data" ); goto error; } /* Set output properties */ if( !p_sys->b_packetizer ) switch( p_sys->ti.pixelformat ) { case OC_PF_420: p_dec->fmt_out.i_codec = VLC_CODEC_I420; break; case OC_PF_422: p_dec->fmt_out.i_codec = VLC_CODEC_I422; break; case OC_PF_444: p_dec->fmt_out.i_codec = VLC_CODEC_I444; break; case OC_PF_RSVD: default: msg_Err( p_dec, "unknown chroma in theora sample" ); break; } p_dec->fmt_out.video.i_width = p_sys->ti.width; p_dec->fmt_out.video.i_height = p_sys->ti.height; if( p_sys->ti.frame_width && p_sys->ti.frame_height ) { p_dec->fmt_out.video.i_visible_width = p_sys->ti.frame_width; p_dec->fmt_out.video.i_visible_height = p_sys->ti.frame_height; if( p_sys->ti.offset_x || p_sys->ti.offset_y ) { p_dec->fmt_out.video.i_x_offset = p_sys->ti.offset_x; p_dec->fmt_out.video.i_y_offset = p_sys->ti.offset_y; } } if( p_sys->ti.aspect_denominator && p_sys->ti.aspect_numerator ) { p_dec->fmt_out.video.i_sar_num = p_sys->ti.aspect_numerator; p_dec->fmt_out.video.i_sar_den = p_sys->ti.aspect_denominator; } else { p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; } if( p_sys->ti.fps_numerator > 0 && p_sys->ti.fps_denominator > 0 ) { p_dec->fmt_out.video.i_frame_rate = p_sys->ti.fps_numerator; p_dec->fmt_out.video.i_frame_rate_base = p_sys->ti.fps_denominator; } msg_Dbg( p_dec, "%dx%d %.02f fps video, frame content " "is %dx%d with offset (%d,%d)", p_sys->ti.width, p_sys->ti.height, (double)p_sys->ti.fps_numerator/p_sys->ti.fps_denominator, p_sys->ti.frame_width, p_sys->ti.frame_height, p_sys->ti.offset_x, p_sys->ti.offset_y ); /* Sanity check that seems necessary for some corrupted files */ if( p_sys->ti.width < p_sys->ti.frame_width || p_sys->ti.height < p_sys->ti.frame_height ) { msg_Warn( p_dec, "trying to correct invalid theora header " "(frame size (%dx%d) is smaller than frame content (%d,%d))", p_sys->ti.width, p_sys->ti.height, p_sys->ti.frame_width, p_sys->ti.frame_height ); if( p_sys->ti.width < p_sys->ti.frame_width ) p_sys->ti.width = p_sys->ti.frame_width; if( p_sys->ti.height < p_sys->ti.frame_height ) p_sys->ti.height = p_sys->ti.frame_height; } /* The next packet in order is the comments header */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[1]; oggpacket.packet = pp_data[1]; if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 ) { msg_Err( p_dec, "2nd Theora header is corrupted" ); goto error; } ParseTheoraComments( p_dec ); /* The next packet in order is the codebooks header * We need to watch out that this packet is not missing as a * missing or corrupted header is fatal. */ oggpacket.b_o_s = 0; oggpacket.bytes = pi_size[2]; oggpacket.packet = pp_data[2]; if( theora_decode_header( &p_sys->ti, &p_sys->tc, &oggpacket ) < 0 ) { msg_Err( p_dec, "3rd Theora header is corrupted" ); goto error; } if( !p_sys->b_packetizer ) { /* We have all the headers, initialize decoder */ theora_decode_init( &p_sys->td, &p_sys->ti ); } else { p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } for( unsigned i = 0; i < i_count; i++ ) free( pp_data[i] ); return VLC_SUCCESS; error: for( unsigned i = 0; i < i_count; i++ ) free( pp_data[i] ); return VLC_EGENERIC; }