static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block ) { decoder_t *p_dec = p_private; decoder_sys_t *p_sys = p_dec->p_sys; const uint8_t *p_buf = &p_block->p_buffer[2]; size_t i_buf = p_block->i_buffer - 2; while( i_buf > 4 && p_buf[0] == 0xFF ) { size_t i_size = 2 + GetWBE( &p_buf[2] ); if( i_size > i_buf ) break; if( p_buf[1] == 0xC0 && i_buf > 9 ) { uint16_t i_height = GetWBE( &p_buf[5] ); uint16_t i_width = GetWBE( &p_buf[7] ); if( i_height && i_width && (p_dec->fmt_out.video.i_height != i_height || p_dec->fmt_out.video.i_width != i_width) ) { p_dec->fmt_out.video.i_width = p_dec->fmt_out.video.i_visible_width = i_width; p_dec->fmt_out.video.i_height = p_dec->fmt_out.video.i_visible_height = i_height; } break; } i_buf -= i_size; p_buf += i_size; } if( p_block->i_dts == VLC_TICK_INVALID ) p_block->i_dts = p_block->i_pts; else if( p_block->i_pts == VLC_TICK_INVALID ) p_block->i_pts = p_block->i_dts; vlc_tick_t i_prev_dts = date_Get( &p_sys->date ); if( p_block->i_dts != VLC_TICK_INVALID ) { date_Set( &p_sys->date, p_block->i_dts ); } else if( p_dec->fmt_in.video.i_frame_rate && p_dec->fmt_in.video.i_frame_rate_base ) { date_Increment( &p_sys->date, 1 ); p_block->i_dts = p_block->i_pts = date_Get( &p_sys->date ); } if( i_prev_dts != VLC_TICK_INVALID && p_block->i_dts != VLC_TICK_INVALID ) p_block->i_length = p_block->i_dts - i_prev_dts; *pb_ts_used = true; p_block->i_flags = p_sys->i_next_block_flags | BLOCK_FLAG_TYPE_I; p_sys->i_next_block_flags = 0; return p_block; }
/***************************************************************************** * EntryPoints: Reads the information about the entry points on the disc. *****************************************************************************/ static int EntryPoints( access_t *p_access ) { access_sys_t *p_sys = p_access->p_sys; uint8_t sector[VCD_DATA_SIZE]; entries_sect_t entries; int i_nb; /* Read the entry point sector */ if( ioctl_ReadSectors( VLC_OBJECT(p_access), p_sys->vcddev, VCD_ENTRIES_SECTOR, sector, 1, VCD_TYPE ) < 0 ) { msg_Err( p_access, "could not read entry points sector" ); return VLC_EGENERIC; } memcpy( &entries, sector, CD_SECTOR_SIZE ); i_nb = GetWBE( &entries.i_entries_nb ); if( i_nb > 500 ) { msg_Err( p_access, "invalid entry points number" ); return VLC_EGENERIC; } if( strncmp( entries.psz_id, "ENTRYVCD", sizeof( entries.psz_id ) ) && strncmp( entries.psz_id, "ENTRYSVD", sizeof( entries.psz_id ) ) ) { msg_Err( p_access, "unrecognized entry points format" ); return VLC_EGENERIC; } for( int i = 0; i < i_nb; i++ ) { const int i_title = BCD_TO_BIN(entries.entry[i].i_track) - 2; const int i_sector = (MSF_TO_LBA2( BCD_TO_BIN( entries.entry[i].msf.minute ), BCD_TO_BIN( entries.entry[i].msf.second ), BCD_TO_BIN( entries.entry[i].msf.frame ) )); seekpoint_t *s; if( i_title < 0 ) continue; /* Should not occur */ if( i_title >= p_sys->i_titles ) continue; msg_Dbg( p_access, "Entry[%d] title=%d sector=%d", i, i_title, i_sector ); s = vlc_seekpoint_New(); s->i_byte_offset = (i_sector - p_sys->p_sectors[i_title+1]) * VCD_DATA_SIZE; TAB_APPEND( p_sys->title[i_title]->i_seekpoint, p_sys->title[i_title]->seekpoint, s ); } return VLC_SUCCESS; }
static void U16BDecode( void *outp, const uint8_t *in, unsigned samples ) { uint16_t *out = outp; for( size_t i = 0; i < samples; i++ ) { *(out++) = GetWBE( in ) - 0x8000; in += 2; } }
/** * Gets a framed RTP packet. * @param fd stream file descriptor * @return a block or NULL in case of fatal error */ static block_t *rtp_stream_recv (vlc_object_t *obj, int fd) { ssize_t len = 0; uint8_t hdr[2]; /* frame header */ /* Receives the RTP frame header */ do { ssize_t val = net_Read (obj, fd, NULL, hdr + len, 2 - len, false); if (val <= 0) return NULL; len += val; } while (len < 2); block_t *block = block_Alloc (GetWBE (hdr)); /* Receives the RTP packet */ for (ssize_t i = 0; i < len;) { ssize_t val; block_cleanup_push (block); val = net_Read (obj, fd, NULL, block->p_buffer + i, block->i_buffer - i, false); vlc_cleanup_pop (); if (val <= 0) { block_Release (block); return NULL; } i += val; } return block; }
/***************************************************************************** * Decode: *****************************************************************************/ static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block ) { block_t *p_block; subpicture_t *p_spu = NULL; if( ( pp_block == NULL ) || ( *pp_block == NULL ) ) return NULL; p_block = *pp_block; *pp_block = NULL; if( ( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) || p_block->i_buffer < sizeof(uint16_t) ) { block_Release( p_block ); return NULL; } uint8_t *p_buf = p_block->p_buffer; /* Read our raw string and create the styled segment for HTML */ uint16_t i_psz_length = GetWBE( p_buf ); char *psz_subtitle = malloc( i_psz_length + 1 ); if ( !psz_subtitle ) return NULL; memcpy( psz_subtitle, p_block->p_buffer + sizeof(uint16_t), i_psz_length ); psz_subtitle[ i_psz_length ] = '\0'; p_buf += i_psz_length + sizeof(uint16_t); for( uint16_t i=0; i < i_psz_length; i++ ) if ( psz_subtitle[i] == '\r' ) psz_subtitle[i] = '\n'; segment_t *p_segment = calloc( 1, sizeof(segment_t) ); if ( !p_segment ) { free( psz_subtitle ); return NULL; } p_segment->psz_string = strdup( psz_subtitle ); p_segment->i_size = strlen( psz_subtitle ); if ( p_dec->fmt_in.subs.p_style ) { p_segment->styles.i_color = p_dec->fmt_in.subs.p_style->i_font_color; p_segment->styles.i_color |= p_dec->fmt_in.subs.p_style->i_font_alpha << 24; if ( p_dec->fmt_in.subs.p_style->i_style_flags ) p_segment->styles.i_flags = p_dec->fmt_in.subs.p_style->i_style_flags; p_segment->styles.i_fontsize = p_dec->fmt_in.subs.p_style->i_font_size; } if ( !p_segment->psz_string ) { SegmentFree( p_segment ); free( psz_subtitle ); return NULL; } /* Create the subpicture unit */ p_spu = decoder_NewSubpictureText( p_dec ); if( !p_spu ) { free( psz_subtitle ); SegmentFree( p_segment ); return NULL; } subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys; /* Parse our styles */ while( (size_t)(p_buf - p_block->p_buffer) + 8 < p_block->i_buffer ) { uint32_t i_atomsize = GetDWBE( p_buf ); vlc_fourcc_t i_atomtype = VLC_FOURCC(p_buf[4],p_buf[5],p_buf[6],p_buf[7]); p_buf += 8; switch( i_atomtype ) { case VLC_FOURCC('s','t','y','l'): { if ( (size_t)(p_buf - p_block->p_buffer) < 14 ) break; uint16_t i_nbrecords = GetWBE(p_buf); uint16_t i_cur_record = 0; p_buf += 2; while( i_cur_record++ < i_nbrecords ) { if ( (size_t)(p_buf - p_block->p_buffer) < 12 ) break; uint16_t i_start = __MIN( GetWBE(p_buf), i_psz_length - 1 ); uint16_t i_end = __MIN( GetWBE(p_buf + 2), i_psz_length - 1 ); segment_style_t style; style.i_flags = ConvertFlags( p_buf[6] ); style.i_fontsize = p_buf[7]; style.i_color = GetDWBE(p_buf+8) >> 8;// RGBA -> ARGB style.i_color |= (GetDWBE(p_buf+8) & 0xFF) << 24; ApplySegmentStyle( &p_segment, i_start, i_end, &style ); if ( i_nbrecords == 1 ) { if ( p_buf[6] ) { p_spu_sys->style_flags.i_value = ConvertFlags( p_buf[6] ); p_spu_sys->style_flags.b_set = true; } p_spu_sys->i_font_height_abs_to_src = p_buf[7]; p_spu_sys->font_color.i_value = GetDWBE(p_buf+8) >> 8;// RGBA -> ARGB p_spu_sys->font_color.i_value |= (GetDWBE(p_buf+8) & 0xFF) << 24; p_spu_sys->font_color.b_set = true; } p_buf += 12; } } break; case VLC_FOURCC('d','r','p','o'): if ( (size_t)(p_buf - p_block->p_buffer) < 4 ) break; p_spu_sys->i_drop_shadow = __MAX( GetWBE(p_buf), GetWBE(p_buf+2) ); break; case VLC_FOURCC('d','r','p','t'): if ( (size_t)(p_buf - p_block->p_buffer) < 2 ) break; p_spu_sys->i_drop_shadow_alpha = GetWBE(p_buf); break; default: break; } p_buf += i_atomsize; } p_spu->i_start = p_block->i_pts; p_spu->i_stop = p_block->i_pts + p_block->i_length; p_spu->b_ephemer = (p_block->i_length == 0); p_spu->b_absolute = false; p_spu_sys->align = SUBPICTURE_ALIGN_BOTTOM; p_spu_sys->text = psz_subtitle; p_spu_sys->p_htmlsegments = p_segment; block_Release( p_block ); return p_spu; }
/***************************************************************************** * Open *****************************************************************************/ static int OpenCommon( vlc_object_t *p_this, bool b_force ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; const uint8_t *p_peek; ssize_t i_peek = 0; ssize_t i_offset = 0; ssize_t i_skip = 0; unsigned i_max_packets = PS_PACKET_PROBE; int format = MPEG_PS; int i_mux_rate = 0; vlc_tick_t i_length = VLC_TICK_INVALID; i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 16 ); if( i_peek < 16 ) { msg_Dbg( p_demux, "cannot peek" ); return VLC_EGENERIC; } if( !memcmp( p_peek, "PSMF", 4 ) && (GetDWBE( &p_peek[4] ) & 0x30303030) == 0x30303030 ) { i_peek = vlc_stream_Peek( p_demux->s, &p_peek, 100 ); if( i_peek < 100 ) return VLC_EGENERIC; i_skip = i_offset = GetWBE( &p_peek[10] ); format = PSMF_PS; msg_Info( p_demux, "Detected PSMF-PS header"); i_mux_rate = GetDWBE( &p_peek[96] ); if( GetDWBE( &p_peek[86] ) > 0 ) i_length = vlc_tick_from_samples( GetDWBE( &p_peek[92] ), GetDWBE( &p_peek[86] )); } else if( !memcmp( p_peek, "RIFF", 4 ) && !memcmp( &p_peek[8], "CDXA", 4 ) ) { format = CDXA_PS; i_max_packets = 0; /* We can't probe here */ i_skip = CDXA_HEADER_SIZE; msg_Info( p_demux, "Detected CDXA-PS" ); /* FIXME: have a proper way to decap CD sectors or make an access stream filter */ } else if( b_force ) { msg_Warn( p_demux, "this does not look like an MPEG PS stream, " "continuing anyway" ); i_max_packets = 0; } for( unsigned i=0; i<i_max_packets; i++ ) { if( i_peek < i_offset + 16 ) { i_peek = vlc_stream_Peek( p_demux->s, &p_peek, i_offset + 16 ); if( i_peek < i_offset + 16 ) return VLC_EGENERIC; } const uint8_t startcode[3] = { 0x00, 0x00, 0x01 }; const uint8_t *p_header = &p_peek[i_offset]; if( memcmp( p_header, startcode, 3 ) || ( (p_header[3] & 0xB0) != 0xB0 && !(p_header[3] >= 0xC0 && p_header[3] <= 0xEF) && p_header[3] != PS_STREAM_ID_EXTENDED && p_header[3] != PS_STREAM_ID_DIRECTORY ) ) return VLC_EGENERIC; ssize_t i_pessize = ps_pkt_size( p_header, 16 ); if( i_pessize < 5 ) return VLC_EGENERIC; i_offset += i_pessize; } if( i_skip > 0 && !p_demux->b_preparsing && vlc_stream_Read( p_demux->s, NULL, i_skip ) != i_skip ) return VLC_EGENERIC; /* Fill p_demux field */ p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_demux->pf_demux = Demux; p_demux->pf_control = Control; /* Init p_sys */ p_sys->i_mux_rate = i_mux_rate; p_sys->i_pack_scr = VLC_TICK_INVALID; p_sys->i_first_scr = VLC_TICK_INVALID; p_sys->i_scr = VLC_TICK_INVALID; p_sys->i_scr_track_id = 0; p_sys->i_length = i_length; p_sys->i_current_pts = VLC_TICK_INVALID; p_sys->i_time_track_index = -1; p_sys->i_aob_mlp_count = 0; p_sys->i_start_byte = i_skip; p_sys->i_lastpack_byte = i_skip; p_sys->b_lost_sync = false; p_sys->b_have_pack = false; p_sys->b_bad_scr = false; p_sys->b_seekable = false; p_sys->format = format; p_sys->current_title = 0; p_sys->current_seekpoint = 0; p_sys->updates = 0; vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable ); ps_psm_init( &p_sys->psm ); ps_track_init( p_sys->tk ); /* TODO prescanning of ES */ return VLC_SUCCESS; }
/***************************************************************************** * Open: probe the packetizer and return score * When opening after demux, the packetizer is only loaded AFTER the decoder * That means that what you set in fmt_out is ignored by the decoder in this special case *****************************************************************************/ static int Open( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'h', '2', '6', '4') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'H', '2', '6', '4') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'V', 'S', 'S', 'H') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'v', 's', 's', 'h') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'D', 'A', 'V', 'C') && ( p_dec->fmt_in.i_codec != VLC_FOURCC( 'a', 'v', 'c', '1') || p_dec->fmt_in.i_extra < 7 ) ) { return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = malloc( sizeof(decoder_sys_t) ) ) == NULL ) { msg_Err( p_dec, "out of memory" ); return VLC_EGENERIC; } p_sys->i_state = STATE_NOSYNC; p_sys->i_offset = 0; p_sys->startcode[0] = 0; p_sys->startcode[1] = 0; p_sys->startcode[2] = 0; p_sys->startcode[3] = 1; p_sys->bytestream = block_BytestreamInit( p_dec ); p_sys->b_slice = VLC_FALSE; p_sys->p_frame = NULL; p_sys->b_sps = VLC_FALSE; p_sys->b_pps = VLC_FALSE; p_sys->p_sps = 0; p_sys->p_pps = 0; p_sys->b_header= VLC_FALSE; p_sys->slice.i_nal_type = -1; p_sys->slice.i_nal_ref_idc = -1; p_sys->slice.i_idr_pic_id = -1; p_sys->slice.i_frame_num = -1; p_sys->slice.i_frame_type = 0; p_sys->slice.i_pic_parameter_set_id = -1; p_sys->slice.i_field_pic_flag = 0; p_sys->slice.i_bottom_field_flag = -1; p_sys->slice.i_pic_order_cnt_lsb = -1; p_sys->slice.i_delta_pic_order_cnt_bottom = -1; /* Setup properties */ es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); p_dec->fmt_out.i_codec = VLC_FOURCC( 'h', '2', '6', '4' ); if( p_dec->fmt_in.i_codec == VLC_FOURCC( 'a', 'v', 'c', '1' ) ) { /* This type of stream is produced by mp4 and matroska * when we want to store it in another streamformat, you need to convert * The fmt_in.p_extra should ALWAYS contain the avcC * The fmt_out.p_extra should contain all the SPS and PPS with 4 byte startcodes */ uint8_t *p = &((uint8_t*)p_dec->fmt_in.p_extra)[4]; int i_sps, i_pps; int i; /* Parse avcC */ p_sys->i_avcC_length_size = 1 + ((*p++)&0x03); /* Read SPS */ i_sps = (*p++)&0x1f; for( i = 0; i < i_sps; i++ ) { int i_length = GetWBE( p ); block_t *p_sps = nal_get_annexeb( p_dec, p + 2, i_length ); p_sys->p_sps = block_Duplicate( p_sps ); p_sps->i_pts = p_sps->i_dts = mdate(); ParseNALBlock( p_dec, p_sps ); p += 2 + i_length; } /* Read PPS */ i_pps = *p++; for( i = 0; i < i_pps; i++ ) { int i_length = GetWBE( p ); block_t *p_pps = nal_get_annexeb( p_dec, p + 2, i_length ); p_sys->p_pps = block_Duplicate( p_pps ); p_pps->i_pts = p_pps->i_dts = mdate(); ParseNALBlock( p_dec, p_pps ); p += 2 + i_length; } msg_Dbg( p_dec, "avcC length size=%d, sps=%d, pps=%d", p_sys->i_avcC_length_size, i_sps, i_pps ); /* FIXME: FFMPEG isn't happy at all if you leave this */ if( p_dec->fmt_out.i_extra ) free( p_dec->fmt_out.p_extra ); p_dec->fmt_out.i_extra = 0; p_dec->fmt_out.p_extra = NULL; /* Set the new extradata */ p_dec->fmt_out.i_extra = p_sys->p_pps->i_buffer + p_sys->p_sps->i_buffer; p_dec->fmt_out.p_extra = (uint8_t*)malloc( p_dec->fmt_out.i_extra ); memcpy( (uint8_t*)p_dec->fmt_out.p_extra, p_sys->p_sps->p_buffer, p_sys->p_sps->i_buffer); memcpy( (uint8_t*)p_dec->fmt_out.p_extra+p_sys->p_sps->i_buffer, p_sys->p_pps->p_buffer, p_sys->p_pps->i_buffer); p_sys->b_header = VLC_TRUE; /* Set callback */ p_dec->pf_packetize = PacketizeAVC1; } else { /* This type of stream contains data with 3 of 4 byte startcodes * The fmt_in.p_extra MAY contain SPS/PPS with 4 byte startcodes * The fmt_out.p_extra should be the same */ /* Set callback */ p_dec->pf_packetize = Packetize; /* */ if( p_dec->fmt_in.i_extra > 0 ) { block_t *p_init = block_New( p_dec, p_dec->fmt_in.i_extra ); block_t *p_pic; memcpy( p_init->p_buffer, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); while( ( p_pic = Packetize( p_dec, &p_init ) ) ) { /* Should not occur because we should only receive SPS/PPS */ block_Release( p_pic ); } } } return VLC_SUCCESS; }
int avformat_OpenDemux( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; AVInputFormat *fmt = NULL; vlc_tick_t i_start_time = VLC_TICK_INVALID; bool b_can_seek; const char *psz_url; int error; if( p_demux->psz_filepath ) psz_url = p_demux->psz_filepath; else psz_url = p_demux->psz_url; if( avformat_ProbeDemux( p_this, &fmt, psz_url ) != VLC_SUCCESS ) return VLC_EGENERIC; vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_can_seek ); /* Fill p_demux fields */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->ic = 0; p_sys->fmt = fmt; p_sys->tracks = NULL; p_sys->i_ssa_order = 0; TAB_INIT( p_sys->i_attachments, p_sys->attachments); p_sys->p_title = NULL; p_sys->i_seekpoint = 0; p_sys->i_update = 0; /* Create I/O wrapper */ unsigned char * p_io_buffer = av_malloc( AVFORMAT_IOBUFFER_SIZE ); if( !p_io_buffer ) { avformat_CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->ic = avformat_alloc_context(); if( !p_sys->ic ) { av_free( p_io_buffer ); avformat_CloseDemux( p_this ); return VLC_ENOMEM; } AVIOContext *pb = p_sys->ic->pb = avio_alloc_context( p_io_buffer, AVFORMAT_IOBUFFER_SIZE, 0, p_demux, IORead, NULL, IOSeek ); if( !pb ) { av_free( p_io_buffer ); avformat_CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->ic->pb->seekable = b_can_seek ? AVIO_SEEKABLE_NORMAL : 0; error = avformat_open_input(&p_sys->ic, psz_url, p_sys->fmt, NULL); if( error < 0 ) { msg_Err( p_demux, "Could not open %s: %s", psz_url, vlc_strerror_c(AVUNERROR(error)) ); av_free( pb->buffer ); av_free( pb ); p_sys->ic = NULL; avformat_CloseDemux( p_this ); return VLC_EGENERIC; } char *psz_opts = var_InheritString( p_demux, "avformat-options" ); unsigned nb_streams = p_sys->ic->nb_streams; AVDictionary *options[nb_streams ? nb_streams : 1]; options[0] = NULL; for (unsigned i = 1; i < nb_streams; i++) options[i] = NULL; if (psz_opts) { vlc_av_get_options(psz_opts, &options[0]); for (unsigned i = 1; i < nb_streams; i++) { av_dict_copy(&options[i], options[0], 0); } free(psz_opts); } vlc_avcodec_lock(); /* avformat calls avcodec behind our back!!! */ error = avformat_find_stream_info( p_sys->ic, options ); vlc_avcodec_unlock(); AVDictionaryEntry *t = NULL; while ((t = av_dict_get(options[0], "", t, AV_DICT_IGNORE_SUFFIX))) { msg_Err( p_demux, "Unknown option \"%s\"", t->key ); } av_dict_free(&options[0]); for (unsigned i = 1; i < nb_streams; i++) { av_dict_free(&options[i]); } nb_streams = p_sys->ic->nb_streams; /* it may have changed */ if( !nb_streams ) { msg_Err( p_demux, "No streams found"); avformat_CloseDemux( p_this ); return VLC_EGENERIC; } p_sys->tracks = calloc( nb_streams, sizeof(*p_sys->tracks) ); if( !p_sys->tracks ) { avformat_CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->i_tracks = nb_streams; if( error < 0 ) { msg_Warn( p_demux, "Could not find stream info: %s", vlc_strerror_c(AVUNERROR(error)) ); } for( unsigned i = 0; i < nb_streams; i++ ) { struct avformat_track_s *p_track = &p_sys->tracks[i]; AVStream *s = p_sys->ic->streams[i]; const AVCodecParameters *cp = s->codecpar; es_format_t es_fmt; const char *psz_type = "unknown"; /* Do not use the cover art as a stream */ if( s->disposition == AV_DISPOSITION_ATTACHED_PIC ) continue; vlc_fourcc_t fcc = GetVlcFourcc( cp->codec_id ); switch( cp->codec_type ) { case AVMEDIA_TYPE_AUDIO: es_format_Init( &es_fmt, AUDIO_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); es_fmt.i_bitrate = cp->bit_rate; es_fmt.audio.i_channels = cp->channels; es_fmt.audio.i_rate = cp->sample_rate; es_fmt.audio.i_bitspersample = cp->bits_per_coded_sample; es_fmt.audio.i_blockalign = cp->block_align; psz_type = "audio"; if(cp->codec_id == AV_CODEC_ID_AAC_LATM) { es_fmt.i_original_fourcc = VLC_FOURCC('L','A','T','M'); es_fmt.b_packetized = false; } else if(cp->codec_id == AV_CODEC_ID_AAC && p_sys->fmt->long_name && strstr(p_sys->fmt->long_name, "raw ADTS AAC")) { es_fmt.i_original_fourcc = VLC_FOURCC('A','D','T','S'); es_fmt.b_packetized = false; } break; case AVMEDIA_TYPE_VIDEO: es_format_Init( &es_fmt, VIDEO_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); es_fmt.video.i_bits_per_pixel = cp->bits_per_coded_sample; /* Special case for raw video data */ if( cp->codec_id == AV_CODEC_ID_RAWVIDEO ) { msg_Dbg( p_demux, "raw video, pixel format: %i", cp->format ); if( GetVlcChroma( &es_fmt.video, cp->format ) != VLC_SUCCESS) { msg_Err( p_demux, "was unable to find a FourCC match for raw video" ); } else es_fmt.i_codec = es_fmt.video.i_chroma; } /* We need this for the h264 packetizer */ else if( cp->codec_id == AV_CODEC_ID_H264 && ( p_sys->fmt == av_find_input_format("flv") || p_sys->fmt == av_find_input_format("matroska") || p_sys->fmt == av_find_input_format("mp4") ) ) es_fmt.i_original_fourcc = VLC_FOURCC( 'a', 'v', 'c', '1' ); es_fmt.video.i_width = cp->width; es_fmt.video.i_height = cp->height; es_fmt.video.i_visible_width = es_fmt.video.i_width; es_fmt.video.i_visible_height = es_fmt.video.i_height; get_rotation(&es_fmt, s); # warning FIXME: implement palette transmission psz_type = "video"; AVRational rate; #if (LIBAVUTIL_VERSION_MICRO < 100) /* libav */ # if (LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(55, 20, 0)) rate.num = s->time_base.num; rate.den = s->time_base.den; # else rate.num = s->codec->time_base.num; rate.den = s->codec->time_base.den; # endif rate.den *= __MAX( s->codec->ticks_per_frame, 1 ); #else /* ffmpeg */ rate = av_guess_frame_rate( p_sys->ic, s, NULL ); #endif if( rate.den && rate.num ) { es_fmt.video.i_frame_rate = rate.num; es_fmt.video.i_frame_rate_base = rate.den; } AVRational ar; #if (LIBAVUTIL_VERSION_MICRO < 100) /* libav */ ar.num = s->sample_aspect_ratio.num; ar.den = s->sample_aspect_ratio.den; #else ar = av_guess_sample_aspect_ratio( p_sys->ic, s, NULL ); #endif if( ar.num && ar.den ) { es_fmt.video.i_sar_den = ar.den; es_fmt.video.i_sar_num = ar.num; } break; case AVMEDIA_TYPE_SUBTITLE: es_format_Init( &es_fmt, SPU_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); if( strncmp( p_sys->ic->iformat->name, "matroska", 8 ) == 0 && cp->codec_id == AV_CODEC_ID_DVD_SUBTITLE && cp->extradata != NULL && cp->extradata_size > 0 ) { char *psz_start; char *psz_buf = malloc( cp->extradata_size + 1); if( psz_buf != NULL ) { memcpy( psz_buf, cp->extradata , cp->extradata_size ); psz_buf[cp->extradata_size] = '\0'; psz_start = strstr( psz_buf, "size:" ); if( psz_start && vobsub_size_parse( psz_start, &es_fmt.subs.spu.i_original_frame_width, &es_fmt.subs.spu.i_original_frame_height ) == VLC_SUCCESS ) { msg_Dbg( p_demux, "original frame size: %dx%d", es_fmt.subs.spu.i_original_frame_width, es_fmt.subs.spu.i_original_frame_height ); } else { msg_Warn( p_demux, "reading original frame size failed" ); } psz_start = strstr( psz_buf, "palette:" ); if( psz_start && vobsub_palette_parse( psz_start, &es_fmt.subs.spu.palette[1] ) == VLC_SUCCESS ) { es_fmt.subs.spu.palette[0] = SPU_PALETTE_DEFINED; msg_Dbg( p_demux, "vobsub palette read" ); } else { msg_Warn( p_demux, "reading original palette failed" ); } free( psz_buf ); } } else if( cp->codec_id == AV_CODEC_ID_DVB_SUBTITLE && cp->extradata_size > 3 ) { es_fmt.subs.dvb.i_id = GetWBE( cp->extradata ) | (GetWBE( cp->extradata + 2 ) << 16); } else if( cp->codec_id == AV_CODEC_ID_MOV_TEXT ) { if( cp->extradata_size && (es_fmt.p_extra = malloc(cp->extradata_size)) ) { memcpy( es_fmt.p_extra, cp->extradata, cp->extradata_size ); es_fmt.i_extra = cp->extradata_size; } } psz_type = "subtitle"; break; default: es_format_Init( &es_fmt, UNKNOWN_ES, 0 ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); #ifdef HAVE_AVUTIL_CODEC_ATTACHMENT if( cp->codec_type == AVMEDIA_TYPE_ATTACHMENT ) { input_attachment_t *p_attachment; psz_type = "attachment"; if( cp->codec_id == AV_CODEC_ID_TTF ) { AVDictionaryEntry *filename = av_dict_get( s->metadata, "filename", NULL, 0 ); if( filename && filename->value ) { p_attachment = vlc_input_attachment_New( filename->value, "application/x-truetype-font", NULL, cp->extradata, (int)cp->extradata_size ); if( p_attachment ) TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); } } else msg_Warn( p_demux, "unsupported attachment type (%u) in avformat demux", cp->codec_id ); } else #endif { if( cp->codec_type == AVMEDIA_TYPE_DATA ) psz_type = "data"; msg_Warn( p_demux, "unsupported track type (%u:%u) in avformat demux", cp->codec_type, cp->codec_id ); } break; } AVDictionaryEntry *language = av_dict_get( s->metadata, "language", NULL, 0 ); if ( language && language->value ) es_fmt.psz_language = strdup( language->value ); if( s->disposition & AV_DISPOSITION_DEFAULT ) es_fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1000; #ifdef HAVE_AVUTIL_CODEC_ATTACHMENT if( cp->codec_type != AVMEDIA_TYPE_ATTACHMENT ) #endif if( cp->codec_type != AVMEDIA_TYPE_DATA ) { const bool b_ogg = !strcmp( p_sys->fmt->name, "ogg" ); const uint8_t *p_extra = cp->extradata; unsigned i_extra = cp->extradata_size; if( cp->codec_id == AV_CODEC_ID_THEORA && b_ogg ) { unsigned pi_size[3]; const void *pp_data[3]; unsigned i_count; for( i_count = 0; i_count < 3; i_count++ ) { if( i_extra < 2 ) break; pi_size[i_count] = GetWBE( p_extra ); pp_data[i_count] = &p_extra[2]; if( i_extra < pi_size[i_count] + 2 ) break; p_extra += 2 + pi_size[i_count]; i_extra -= 2 + pi_size[i_count]; } if( i_count > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, i_count ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->codec_id == AV_CODEC_ID_SPEEX && b_ogg ) { const uint8_t p_dummy_comment[] = { 0, 0, 0, 0, 0, 0, 0, 0, }; unsigned pi_size[2]; const void *pp_data[2]; pi_size[0] = i_extra; pp_data[0] = p_extra; pi_size[1] = sizeof(p_dummy_comment); pp_data[1] = p_dummy_comment; if( pi_size[0] > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, 2 ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->codec_id == AV_CODEC_ID_OPUS ) { const uint8_t p_dummy_comment[] = { 'O', 'p', 'u', 's', 'T', 'a', 'g', 's', 0, 0, 0, 0, /* Vendor String length */ /* Vendor String */ 0, 0, 0, 0, /* User Comment List Length */ }; unsigned pi_size[2]; const void *pp_data[2]; pi_size[0] = i_extra; pp_data[0] = p_extra; pi_size[1] = sizeof(p_dummy_comment); pp_data[1] = p_dummy_comment; if( pi_size[0] > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, 2 ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->extradata_size > 0 && !es_fmt.i_extra ) { es_fmt.p_extra = malloc( i_extra ); if( es_fmt.p_extra ) { es_fmt.i_extra = i_extra; memcpy( es_fmt.p_extra, p_extra, i_extra ); } } p_track->p_es = es_out_Add( p_demux->out, &es_fmt ); if( p_track->p_es && (s->disposition & AV_DISPOSITION_DEFAULT) ) es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, p_track->p_es ); msg_Dbg( p_demux, "adding es: %s codec = %4.4s (%d)", psz_type, (char*)&fcc, cp->codec_id ); } es_format_Clean( &es_fmt ); } if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) i_start_time = FROM_AV_TS(p_sys->ic->start_time); msg_Dbg( p_demux, "AVFormat(%s %s) supported stream", AVPROVIDER(LIBAVFORMAT), LIBAVFORMAT_IDENT ); msg_Dbg( p_demux, " - format = %s (%s)", p_sys->fmt->name, p_sys->fmt->long_name ); msg_Dbg( p_demux, " - start time = %"PRId64, i_start_time ); msg_Dbg( p_demux, " - duration = %"PRId64, ( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) ? FROM_AV_TS(p_sys->ic->duration) : -1 ); if( p_sys->ic->nb_chapters > 0 ) { p_sys->p_title = vlc_input_title_New(); p_sys->p_title->i_length = FROM_AV_TS(p_sys->ic->duration); } for( unsigned i = 0; i < p_sys->ic->nb_chapters; i++ ) { seekpoint_t *s = vlc_seekpoint_New(); AVDictionaryEntry *title = av_dict_get( p_sys->ic->metadata, "title", NULL, 0); if( title && title->value ) { s->psz_name = strdup( title->value ); EnsureUTF8( s->psz_name ); msg_Dbg( p_demux, " - chapter %d: %s", i, s->psz_name ); } s->i_time_offset = vlc_tick_from_samples( p_sys->ic->chapters[i]->start * p_sys->ic->chapters[i]->time_base.num, p_sys->ic->chapters[i]->time_base.den ) - (i_start_time != VLC_TICK_INVALID ? i_start_time : 0 ); TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); } ResetTime( p_demux, 0 ); return VLC_SUCCESS; }
/***************************************************************************** * Open: probe the packetizer and return score * When opening after demux, the packetizer is only loaded AFTER the decoder * That means that what you set in fmt_out is ignored by the decoder in this special case *****************************************************************************/ static int Open( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; int i; if( p_dec->fmt_in.i_codec != VLC_CODEC_H264 ) return VLC_EGENERIC; if( p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'a', 'v', 'c', '1') && p_dec->fmt_in.i_extra < 7 ) return VLC_EGENERIC; /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = malloc( sizeof(decoder_sys_t) ) ) == NULL ) { return VLC_ENOMEM; } packetizer_Init( &p_sys->packetizer, p_h264_startcode, sizeof(p_h264_startcode), p_h264_startcode, 1, 5, PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); p_sys->b_slice = false; p_sys->p_frame = NULL; p_sys->b_frame_sps = false; p_sys->b_frame_pps = false; p_sys->b_header= false; p_sys->b_sps = false; p_sys->b_pps = false; for( i = 0; i < SPS_MAX; i++ ) p_sys->pp_sps[i] = NULL; for( i = 0; i < PPS_MAX; i++ ) p_sys->pp_pps[i] = NULL; p_sys->i_recovery_frames = -1; p_sys->slice.i_nal_type = -1; p_sys->slice.i_nal_ref_idc = -1; p_sys->slice.i_idr_pic_id = -1; p_sys->slice.i_frame_num = -1; p_sys->slice.i_frame_type = 0; p_sys->slice.i_pic_parameter_set_id = -1; p_sys->slice.i_field_pic_flag = 0; p_sys->slice.i_bottom_field_flag = -1; p_sys->slice.i_pic_order_cnt_lsb = -1; p_sys->slice.i_delta_pic_order_cnt_bottom = -1; p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; /* Setup properties */ es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); p_dec->fmt_out.i_codec = VLC_CODEC_H264; if( p_dec->fmt_in.i_original_fourcc == VLC_FOURCC( 'a', 'v', 'c', '1' ) ) { /* This type of stream is produced by mp4 and matroska * when we want to store it in another streamformat, you need to convert * The fmt_in.p_extra should ALWAYS contain the avcC * The fmt_out.p_extra should contain all the SPS and PPS with 4 byte startcodes */ uint8_t *p = &((uint8_t*)p_dec->fmt_in.p_extra)[4]; int i_sps, i_pps; bool b_dummy; int i; /* Parse avcC */ p_sys->i_avcC_length_size = 1 + ((*p++)&0x03); /* Read SPS */ i_sps = (*p++)&0x1f; for( i = 0; i < i_sps; i++ ) { uint16_t i_length = GetWBE( p ); p += 2; if( i_length > (uint8_t*)p_dec->fmt_in.p_extra + p_dec->fmt_in.i_extra - p ) { return VLC_EGENERIC; } block_t *p_sps = CreateAnnexbNAL( p_dec, p, i_length ); if( !p_sps ) return VLC_EGENERIC; ParseNALBlock( p_dec, &b_dummy, p_sps ); p += i_length; } /* Read PPS */ i_pps = *p++; for( i = 0; i < i_pps; i++ ) { uint16_t i_length = GetWBE( p ); p += 2; if( i_length > (uint8_t*)p_dec->fmt_in.p_extra + p_dec->fmt_in.i_extra - p ) { return VLC_EGENERIC; } block_t *p_pps = CreateAnnexbNAL( p_dec, p, i_length ); if( !p_pps ) return VLC_EGENERIC; ParseNALBlock( p_dec, &b_dummy, p_pps ); p += i_length; } msg_Dbg( p_dec, "avcC length size=%d, sps=%d, pps=%d", p_sys->i_avcC_length_size, i_sps, i_pps ); if( !p_sys->b_sps || !p_sys->b_pps ) return VLC_EGENERIC; /* FIXME: FFMPEG isn't happy at all if you leave this */ if( p_dec->fmt_out.i_extra > 0 ) free( p_dec->fmt_out.p_extra ); p_dec->fmt_out.i_extra = 0; p_dec->fmt_out.p_extra = NULL; /* Set the new extradata */ for( i = 0; i < SPS_MAX; i++ ) { if( p_sys->pp_sps[i] ) p_dec->fmt_out.i_extra += p_sys->pp_sps[i]->i_buffer; } for( i = 0; i < PPS_MAX; i++ ) { if( p_sys->pp_pps[i] ) p_dec->fmt_out.i_extra += p_sys->pp_pps[i]->i_buffer; } p_dec->fmt_out.p_extra = malloc( p_dec->fmt_out.i_extra ); if( p_dec->fmt_out.p_extra ) { uint8_t *p_dst = p_dec->fmt_out.p_extra; for( i = 0; i < SPS_MAX; i++ ) { if( p_sys->pp_sps[i] ) { memcpy( p_dst, p_sys->pp_sps[i]->p_buffer, p_sys->pp_sps[i]->i_buffer ); p_dst += p_sys->pp_sps[i]->i_buffer; } } for( i = 0; i < PPS_MAX; i++ ) { if( p_sys->pp_pps[i] ) { memcpy( p_dst, p_sys->pp_pps[i]->p_buffer, p_sys->pp_pps[i]->i_buffer ); p_dst += p_sys->pp_pps[i]->i_buffer; } } p_sys->b_header = true; } else { p_dec->fmt_out.i_extra = 0; } /* Set callback */ p_dec->pf_packetize = PacketizeAVC1; /* TODO CC ? */ } else { /* This type of stream contains data with 3 of 4 byte startcodes * The fmt_in.p_extra MAY contain SPS/PPS with 4 byte startcodes * The fmt_out.p_extra should be the same */ /* Set callback */ p_dec->pf_packetize = Packetize; p_dec->pf_get_cc = GetCc; /* */ p_sys->i_cc_pts = VLC_TS_INVALID; p_sys->i_cc_dts = VLC_TS_INVALID; p_sys->i_cc_flags = 0; cc_Init( &p_sys->cc ); cc_Init( &p_sys->cc_next ); /* */ if( p_dec->fmt_in.i_extra > 0 ) packetizer_Header( &p_sys->packetizer, p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra ); } return VLC_SUCCESS; }
void scan_session_Clean( scan_t *p_scan, scan_session_t *p_session ) { const int i_service_start = p_scan->i_service; dvbpsi_pat_t *p_pat = p_session->p_pat; dvbpsi_sdt_t *p_sdt = p_session->p_sdt; #ifdef DVBPSI_USE_NIT dvbpsi_nit_t *p_nit = p_session->p_nit; #endif if( p_pat ) { /* Parse PAT */ dvbpsi_pat_program_t *p_program; for( p_program = p_pat->p_first_program; p_program != NULL; p_program = p_program->p_next ) { if( p_program->i_number == 0 ) /* NIT */ continue; scan_service_t *s = scan_service_New( p_program->i_number, &p_session->cfg ); TAB_APPEND( p_scan->i_service, p_scan->pp_service, s ); } } /* Parse SDT */ if( p_pat && p_sdt ) { dvbpsi_sdt_service_t *p_srv; for( p_srv = p_sdt->p_first_service; p_srv; p_srv = p_srv->p_next ) { scan_service_t *s = ScanFindService( p_scan, i_service_start, p_srv->i_service_id ); dvbpsi_descriptor_t *p_dr; if( s ) s->b_crypted = p_srv->b_free_ca; for( p_dr = p_srv->p_first_descriptor; p_dr; p_dr = p_dr->p_next ) { if( p_dr->i_tag == 0x48 ) { dvbpsi_service_dr_t *pD = dvbpsi_DecodeServiceDr( p_dr ); if( s ) { if( !s->psz_name ) s->psz_name = dvbsi_to_utf8( pD->i_service_name, pD->i_service_name_length ); if( s->type == SERVICE_UNKNOWN ) { switch( pD->i_service_type ) { case 0x01: s->type = SERVICE_DIGITAL_TELEVISION; break; case 0x02: s->type = SERVICE_DIGITAL_RADIO; break; case 0x16: s->type = SERVICE_DIGITAL_TELEVISION_AC_SD; break; case 0x19: s->type = SERVICE_DIGITAL_TELEVISION_AC_HD; break; } } } } } } } #ifdef DVBPSI_USE_NIT /* Parse NIT */ if( p_pat && p_nit ) { dvbpsi_nit_ts_t *p_ts; for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next ) { uint32_t i_private_data_id = 0; dvbpsi_descriptor_t *p_dsc; if( p_ts->i_orig_network_id != p_nit->i_network_id || p_ts->i_ts_id != p_pat->i_ts_id ) continue; for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next ) { if( p_dsc->i_tag == 0x5f ) { i_private_data_id = GetDWBE( &p_dsc->p_data[0] ); } else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 ) { for( int i = 0; i < p_dsc->i_length/4; i++ ) { uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] ); int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff; scan_service_t *s = ScanFindService( p_scan, i_service_start, i_service_id ); if( s && s->i_channel < 0 ) s->i_channel = i_channel_number; } } } } } #endif /* */ for( int i = i_service_start; i < p_scan->i_service; i++ ) { scan_service_t *p_srv = p_scan->pp_service[i]; p_srv->i_snr = p_session->i_snr; if( p_sdt ) p_srv->i_sdt_version = p_sdt->i_version; #ifdef DVBPSI_USE_NIT if( p_nit ) { p_srv->i_network_id = p_nit->i_network_id; p_srv->i_nit_version = p_nit->i_version; } #endif } /* */ if( p_session->pat ) dvbpsi_DetachPAT( p_session->pat ); if( p_session->p_pat ) dvbpsi_DeletePAT( p_session->p_pat ); if( p_session->sdt ) dvbpsi_DetachDemux( p_session->sdt ); if( p_session->p_sdt ) dvbpsi_DeleteSDT( p_session->p_sdt ); #ifdef DVBPSI_USE_NIT if( p_session->nit ) dvbpsi_DetachDemux( p_session->nit ); if( p_session->p_nit ) dvbpsi_DeleteNIT( p_session->p_nit ); #endif }
/***************************************************************************** * ParseID3Tag : parse an id3tag into the info structures *****************************************************************************/ static void ParseID3Tag( demux_meta_t *p_demux_meta, const uint8_t *p_data, int i_size ) { struct id3_tag *p_id3_tag; struct id3_frame *p_frame; vlc_meta_t *p_meta; int i; p_id3_tag = id3_tag_parse( p_data, i_size ); if( !p_id3_tag ) return; if( !p_demux_meta->p_meta ) p_demux_meta->p_meta = vlc_meta_New(); p_meta = p_demux_meta->p_meta; #define ID_IS( a ) (!strcmp( p_frame->id, a )) #define DESCR_IS( a) strstr( (char*)p_frame->description, a ) #define GET_STRING(frame,fidx) id3_ucs4_latin1duplicate( id3_field_getstring( &(frame)->fields[fidx] ) ) /* */ for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "UFID", i )) != NULL; i++ ) { const char *psz_owner = id3_field_getlatin1( &p_frame->fields[0] ); if( !strncmp( psz_owner, "http://musicbrainz.org", 22 ) ) { id3_byte_t const * p_ufid; id3_length_t i_ufidlen; p_ufid = id3_field_getbinarydata( &p_frame->fields[1], &i_ufidlen ); char *psz_ufid = strndup( p_ufid, i_ufidlen ); vlc_meta_SetTrackID( p_meta, psz_ufid ); free( psz_ufid ); } } /* User defined text (TXXX) */ for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "TXXX", i )) != NULL; i++ ) { /* 3 fields: 'encoding', 'description', 'value' */ char *psz_name = GET_STRING( p_frame, 1 ); char *psz_value = GET_STRING( p_frame, 2 ); vlc_meta_AddExtra( p_meta, psz_name, psz_value ); #if 0 if( !strncmp( psz_name, "MusicBrainz Artist Id", 21 ) ) vlc_meta_SetArtistID( p_meta, psz_value ); if( !strncmp( psz_desc, "MusicBrainz Album Id", 20 ) ) vlc_meta_SetAlbumID( p_meta, psz_value ); #endif free( psz_name ); free( psz_value ); } /* Relative volume adjustment */ for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "RVA2", i )) != NULL; i++ ) { /* 2 fields: 'latin1', 'binary' */ const char *psz_type = id3_field_getlatin1( &p_frame->fields[0] ); if( !strcasecmp( psz_type, "track" ) || !strcasecmp( psz_type, "album" ) || !strcasecmp( psz_type, "normalize" ) ) { id3_byte_t const * p_data; id3_length_t i_data; p_data = id3_field_getbinarydata( &p_frame->fields[1], &i_data ); while( i_data >= 4 ) { const unsigned int i_peak_size = p_data[3]; const float f_temp = GetWBE( &p_data[1] ); const float f_gain = f_temp / 512.0; char psz_value[32]; if( i_data < i_peak_size + 4 ) break; /* only master volume */ if( p_data[0] == 0x01 ) { snprintf( psz_value, sizeof(psz_value), "%f", f_gain ); if( !strcasecmp( psz_type, "album" ) ) vlc_meta_AddExtra( p_meta, "REPLAYGAIN_ALBUM_GAIN", psz_value ); else vlc_meta_AddExtra( p_meta, "REPLAYGAIN_TRACK_GAIN", psz_value ); /* XXX I have no idea what peak unit is ... */ } i_data -= 4+i_peak_size; } } } /* TODO 'RGAD' if it is used somewhere */ /* T--- Text informations */ for( i = 0; (p_frame = id3_tag_findframe( p_id3_tag, "T", i )) != NULL; i++ ) { unsigned i_strings; /* Special case TXXX is not the same beast */ if( ID_IS( "TXXX" ) ) continue; i_strings = id3_field_getnstrings( &p_frame->fields[1] ); while( i_strings > 0 ) { char *psz_temp = id3_ucs4_utf8duplicate( id3_field_getstrings( &p_frame->fields[1], --i_strings ) ); if( ID_IS( ID3_FRAME_GENRE ) ) { char *psz_endptr; int i_genre = strtol( psz_temp, &psz_endptr, 10 ); if( psz_temp != psz_endptr && i_genre >= 0 && i_genre < NUM_GENRES ) { vlc_meta_SetGenre( p_meta, ppsz_genres[atoi(psz_temp)]); } else { /* Unknown genre */ vlc_meta_SetGenre( p_meta,psz_temp ); } } else if( ID_IS( ID3_FRAME_TITLE ) ) { vlc_meta_SetTitle( p_meta, psz_temp ); } else if( ID_IS( ID3_FRAME_ARTIST ) ) { vlc_meta_SetArtist( p_meta, psz_temp ); } else if( ID_IS( ID3_FRAME_YEAR ) ) { vlc_meta_SetDate( p_meta, psz_temp ); } else if( ID_IS( ID3_FRAME_COMMENT ) ) { vlc_meta_SetDescription( p_meta, psz_temp ); } else if( DESCR_IS( "Copyright" ) ) { vlc_meta_SetCopyright( p_meta, psz_temp ); } else if( DESCR_IS( "Publisher" ) ) { vlc_meta_SetPublisher( p_meta, psz_temp ); } else if( DESCR_IS( "Track number/position in set" ) ) { vlc_meta_SetTrackNum( p_meta, psz_temp ); } else if( DESCR_IS( "Album/movie/show title" ) ) { vlc_meta_SetAlbum( p_meta, psz_temp ); } else if( DESCR_IS( "Encoded by" ) ) { vlc_meta_SetEncodedBy( p_meta, psz_temp ); } else if( ID_IS ( "APIC" ) ) { msg_Dbg( p_demux_meta, "** Has APIC **" ); } else if( p_frame->description ) { /* Unhandled meta */ vlc_meta_AddExtra( p_meta, (char*)p_frame->description, psz_temp ); } free( psz_temp ); } } id3_tag_delete( p_id3_tag ); #undef GET_STRING #undef DESCR_IS #undef ID_IS }
int OpenDemux( vlc_object_t *p_this ) { demux_t *p_demux = (demux_t*)p_this; demux_sys_t *p_sys; AVProbeData pd = { }; AVInputFormat *fmt = NULL; int64_t i_start_time = -1; bool b_can_seek; char *psz_url; const uint8_t *peek; int error; /* Init Probe data */ pd.buf_size = vlc_stream_Peek( p_demux->s, &peek, 2048 + 213 ); if( pd.buf_size <= 0 ) { msg_Warn( p_demux, "cannot peek" ); return VLC_EGENERIC; } pd.buf = malloc( pd.buf_size + AVPROBE_PADDING_SIZE ); if( unlikely(pd.buf == NULL) ) return VLC_ENOMEM; memcpy( pd.buf, peek, pd.buf_size ); memset( pd.buf + pd.buf_size, 0, AVPROBE_PADDING_SIZE ); if( p_demux->psz_file ) psz_url = strdup( p_demux->psz_file ); else { if( asprintf( &psz_url, "%s://%s", p_demux->psz_access, p_demux->psz_location ) == -1) psz_url = NULL; } if( psz_url != NULL ) msg_Dbg( p_demux, "trying url: %s", psz_url ); pd.filename = psz_url; vlc_stream_Control( p_demux->s, STREAM_CAN_SEEK, &b_can_seek ); vlc_init_avformat(p_this); /* Guess format */ char *psz_format = var_InheritString( p_this, "avformat-format" ); if( psz_format ) { if( (fmt = av_find_input_format(psz_format)) ) msg_Dbg( p_demux, "forcing format: %s", fmt->name ); free( psz_format ); } if( fmt == NULL ) fmt = av_probe_input_format( &pd, 1 ); free( pd.buf ); if( fmt == NULL ) { msg_Dbg( p_demux, "couldn't guess format" ); free( psz_url ); return VLC_EGENERIC; } if( !p_demux->obj.force ) { static const char ppsz_blacklist[][16] = { /* Don't handle MPEG unless forced */ "mpeg", "vcd", "vob", "mpegts", /* libavformat's redirector won't work */ "redir", "sdp", /* Don't handle subtitles format */ "ass", "srt", "microdvd", /* No timestamps at all */ "hevc", "h264", "" }; for( int i = 0; *ppsz_blacklist[i]; i++ ) { if( !strcmp( fmt->name, ppsz_blacklist[i] ) ) { free( psz_url ); return VLC_EGENERIC; } } } /* Don't trigger false alarms on bin files */ if( !p_demux->obj.force && !strcmp( fmt->name, "psxstr" ) ) { int i_len; if( !p_demux->psz_file ) { free( psz_url ); return VLC_EGENERIC; } i_len = strlen( p_demux->psz_file ); if( i_len < 4 ) { free( psz_url ); return VLC_EGENERIC; } if( strcasecmp( &p_demux->psz_file[i_len - 4], ".str" ) && strcasecmp( &p_demux->psz_file[i_len - 4], ".xai" ) && strcasecmp( &p_demux->psz_file[i_len - 3], ".xa" ) ) { free( psz_url ); return VLC_EGENERIC; } } msg_Dbg( p_demux, "detected format: %s", fmt->name ); /* Fill p_demux fields */ p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys = xmalloc( sizeof( demux_sys_t ) ); p_sys->ic = 0; p_sys->fmt = fmt; p_sys->i_tk = 0; p_sys->tk = NULL; p_sys->tk_pcr = NULL; p_sys->i_ssa_order = 0; TAB_INIT( p_sys->i_attachments, p_sys->attachments); p_sys->p_title = NULL; /* Create I/O wrapper */ unsigned char * p_io_buffer = av_malloc( AVFORMAT_IOBUFFER_SIZE ); if( !p_io_buffer ) { free( psz_url ); CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->ic = avformat_alloc_context(); if( !p_sys->ic ) { av_free( p_io_buffer ); free( psz_url ); CloseDemux( p_this ); return VLC_ENOMEM; } AVIOContext *pb = p_sys->ic->pb = avio_alloc_context( p_io_buffer, AVFORMAT_IOBUFFER_SIZE, 0, p_demux, IORead, NULL, IOSeek ); if( !pb ) { av_free( p_io_buffer ); free( psz_url ); CloseDemux( p_this ); return VLC_ENOMEM; } p_sys->ic->pb->seekable = b_can_seek ? AVIO_SEEKABLE_NORMAL : 0; error = avformat_open_input(&p_sys->ic, psz_url, p_sys->fmt, NULL); if( error < 0 ) { msg_Err( p_demux, "Could not open %s: %s", psz_url, vlc_strerror_c(AVUNERROR(error)) ); av_free( p_io_buffer ); av_free( pb ); p_sys->ic = NULL; free( psz_url ); CloseDemux( p_this ); return VLC_EGENERIC; } free( psz_url ); char *psz_opts = var_InheritString( p_demux, "avformat-options" ); AVDictionary *options[p_sys->ic->nb_streams ? p_sys->ic->nb_streams : 1]; options[0] = NULL; unsigned int nb_streams = p_sys->ic->nb_streams; for (unsigned i = 1; i < nb_streams; i++) options[i] = NULL; if (psz_opts) { vlc_av_get_options(psz_opts, &options[0]); for (unsigned i = 1; i < nb_streams; i++) { av_dict_copy(&options[i], options[0], 0); } free(psz_opts); } vlc_avcodec_lock(); /* avformat calls avcodec behind our back!!! */ error = avformat_find_stream_info( p_sys->ic, options ); /* FIXME: what if nb_streams change after that call? */ vlc_avcodec_unlock(); AVDictionaryEntry *t = NULL; while ((t = av_dict_get(options[0], "", t, AV_DICT_IGNORE_SUFFIX))) { msg_Err( p_demux, "Unknown option \"%s\"", t->key ); } av_dict_free(&options[0]); for (unsigned i = 1; i < nb_streams; i++) { av_dict_free(&options[i]); } if( error < 0 ) { msg_Warn( p_demux, "Could not find stream info: %s", vlc_strerror_c(AVUNERROR(error)) ); } for( unsigned i = 0; i < p_sys->ic->nb_streams; i++ ) { AVStream *s = p_sys->ic->streams[i]; const AVCodecParameters *cp = s->codecpar; es_out_id_t *es = NULL; es_format_t es_fmt; const char *psz_type = "unknown"; /* Do not use the cover art as a stream */ if( s->disposition == AV_DISPOSITION_ATTACHED_PIC ) { TAB_APPEND( p_sys->i_tk, p_sys->tk, NULL ); continue; } vlc_fourcc_t fcc = GetVlcFourcc( cp->codec_id ); switch( cp->codec_type ) { case AVMEDIA_TYPE_AUDIO: es_format_Init( &es_fmt, AUDIO_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); es_fmt.i_bitrate = cp->bit_rate; es_fmt.audio.i_channels = cp->channels; es_fmt.audio.i_rate = cp->sample_rate; es_fmt.audio.i_bitspersample = cp->bits_per_coded_sample; es_fmt.audio.i_blockalign = cp->block_align; psz_type = "audio"; if(cp->codec_id == AV_CODEC_ID_AAC_LATM) { es_fmt.i_original_fourcc = VLC_FOURCC('L','A','T','M'); es_fmt.b_packetized = false; } else if(cp->codec_id == AV_CODEC_ID_AAC && strstr(p_sys->fmt->long_name, "raw ADTS AAC")) { es_fmt.i_original_fourcc = VLC_FOURCC('A','D','T','S'); es_fmt.b_packetized = false; } break; case AVMEDIA_TYPE_VIDEO: es_format_Init( &es_fmt, VIDEO_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); es_fmt.video.i_bits_per_pixel = cp->bits_per_coded_sample; /* Special case for raw video data */ if( cp->codec_id == AV_CODEC_ID_RAWVIDEO ) { msg_Dbg( p_demux, "raw video, pixel format: %i", cp->format ); if( GetVlcChroma( &es_fmt.video, cp->format ) != VLC_SUCCESS) { msg_Err( p_demux, "was unable to find a FourCC match for raw video" ); } else es_fmt.i_codec = es_fmt.video.i_chroma; } /* We need this for the h264 packetizer */ else if( cp->codec_id == AV_CODEC_ID_H264 && ( p_sys->fmt == av_find_input_format("flv") || p_sys->fmt == av_find_input_format("matroska") || p_sys->fmt == av_find_input_format("mp4") ) ) es_fmt.i_original_fourcc = VLC_FOURCC( 'a', 'v', 'c', '1' ); es_fmt.video.i_width = cp->width; es_fmt.video.i_height = cp->height; es_fmt.video.i_visible_width = es_fmt.video.i_width; es_fmt.video.i_visible_height = es_fmt.video.i_height; get_rotation(&es_fmt, s); # warning FIXME: implement palette transmission psz_type = "video"; es_fmt.video.i_frame_rate = s->codec->time_base.num; es_fmt.video.i_frame_rate_base = s->codec->time_base.den * __MAX( s->codec->ticks_per_frame, 1 ); es_fmt.video.i_sar_num = s->sample_aspect_ratio.num; if (s->sample_aspect_ratio.num > 0) es_fmt.video.i_sar_den = s->sample_aspect_ratio.den; else es_fmt.video.i_sar_den = 0; break; case AVMEDIA_TYPE_SUBTITLE: es_format_Init( &es_fmt, SPU_ES, fcc ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); if( strncmp( p_sys->ic->iformat->name, "matroska", 8 ) == 0 && cp->codec_id == AV_CODEC_ID_DVD_SUBTITLE && cp->extradata != NULL && cp->extradata_size > 0 ) { char *psz_start; char *psz_buf = malloc( cp->extradata_size + 1); if( psz_buf != NULL ) { memcpy( psz_buf, cp->extradata , cp->extradata_size ); psz_buf[cp->extradata_size] = '\0'; psz_start = strstr( psz_buf, "size:" ); if( psz_start && vobsub_size_parse( psz_start, &es_fmt.subs.spu.i_original_frame_width, &es_fmt.subs.spu.i_original_frame_height ) == VLC_SUCCESS ) { msg_Dbg( p_demux, "original frame size: %dx%d", es_fmt.subs.spu.i_original_frame_width, es_fmt.subs.spu.i_original_frame_height ); } else { msg_Warn( p_demux, "reading original frame size failed" ); } psz_start = strstr( psz_buf, "palette:" ); if( psz_start && vobsub_palette_parse( psz_start, &es_fmt.subs.spu.palette[1] ) == VLC_SUCCESS ) { es_fmt.subs.spu.palette[0] = SPU_PALETTE_DEFINED; msg_Dbg( p_demux, "vobsub palette read" ); } else { msg_Warn( p_demux, "reading original palette failed" ); } free( psz_buf ); } } psz_type = "subtitle"; break; default: es_format_Init( &es_fmt, UNKNOWN_ES, 0 ); es_fmt.i_original_fourcc = CodecTagToFourcc( cp->codec_tag ); #ifdef HAVE_AVUTIL_CODEC_ATTACHMENT if( cp->codec_type == AVMEDIA_TYPE_ATTACHMENT ) { input_attachment_t *p_attachment; psz_type = "attachment"; if( cp->codec_id == AV_CODEC_ID_TTF ) { AVDictionaryEntry *filename = av_dict_get( s->metadata, "filename", NULL, 0 ); if( filename && filename->value ) { p_attachment = vlc_input_attachment_New( filename->value, "application/x-truetype-font", NULL, cp->extradata, (int)cp->extradata_size ); if( p_attachment ) TAB_APPEND( p_sys->i_attachments, p_sys->attachments, p_attachment ); } } else msg_Warn( p_demux, "unsupported attachment type (%u) in avformat demux", cp->codec_id ); } else #endif { if( cp->codec_type == AVMEDIA_TYPE_DATA ) psz_type = "data"; msg_Warn( p_demux, "unsupported track type (%u:%u) in avformat demux", cp->codec_type, cp->codec_id ); } break; } AVDictionaryEntry *language = av_dict_get( s->metadata, "language", NULL, 0 ); if ( language && language->value ) es_fmt.psz_language = strdup( language->value ); if( s->disposition & AV_DISPOSITION_DEFAULT ) es_fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1000; #ifdef HAVE_AVUTIL_CODEC_ATTACHMENT if( cp->codec_type != AVMEDIA_TYPE_ATTACHMENT ) #endif if( cp->codec_type != AVMEDIA_TYPE_DATA ) { const bool b_ogg = !strcmp( p_sys->fmt->name, "ogg" ); const uint8_t *p_extra = cp->extradata; unsigned i_extra = cp->extradata_size; if( cp->codec_id == AV_CODEC_ID_THEORA && b_ogg ) { unsigned pi_size[3]; const void *pp_data[3]; unsigned i_count; for( i_count = 0; i_count < 3; i_count++ ) { if( i_extra < 2 ) break; pi_size[i_count] = GetWBE( p_extra ); pp_data[i_count] = &p_extra[2]; if( i_extra < pi_size[i_count] + 2 ) break; p_extra += 2 + pi_size[i_count]; i_extra -= 2 + pi_size[i_count]; } if( i_count > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, i_count ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->codec_id == AV_CODEC_ID_SPEEX && b_ogg ) { const uint8_t p_dummy_comment[] = { 0, 0, 0, 0, 0, 0, 0, 0, }; unsigned pi_size[2]; const void *pp_data[2]; pi_size[0] = i_extra; pp_data[0] = p_extra; pi_size[1] = sizeof(p_dummy_comment); pp_data[1] = p_dummy_comment; if( pi_size[0] > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, 2 ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->codec_id == AV_CODEC_ID_OPUS ) { const uint8_t p_dummy_comment[] = { 'O', 'p', 'u', 's', 'T', 'a', 'g', 's', 0, 0, 0, 0, /* Vendor String length */ /* Vendor String */ 0, 0, 0, 0, /* User Comment List Length */ }; unsigned pi_size[2]; const void *pp_data[2]; pi_size[0] = i_extra; pp_data[0] = p_extra; pi_size[1] = sizeof(p_dummy_comment); pp_data[1] = p_dummy_comment; if( pi_size[0] > 0 && xiph_PackHeaders( &es_fmt.i_extra, &es_fmt.p_extra, pi_size, pp_data, 2 ) ) { es_fmt.i_extra = 0; es_fmt.p_extra = NULL; } } else if( cp->extradata_size > 0 ) { es_fmt.p_extra = malloc( i_extra ); if( es_fmt.p_extra ) { es_fmt.i_extra = i_extra; memcpy( es_fmt.p_extra, p_extra, i_extra ); } } es = es_out_Add( p_demux->out, &es_fmt ); if( s->disposition & AV_DISPOSITION_DEFAULT ) es_out_Control( p_demux->out, ES_OUT_SET_ES_DEFAULT, es ); es_format_Clean( &es_fmt ); msg_Dbg( p_demux, "adding es: %s codec = %4.4s (%d)", psz_type, (char*)&fcc, cp->codec_id ); } TAB_APPEND( p_sys->i_tk, p_sys->tk, es ); } p_sys->tk_pcr = xcalloc( p_sys->i_tk, sizeof(*p_sys->tk_pcr) ); if( p_sys->ic->start_time != (int64_t)AV_NOPTS_VALUE ) i_start_time = p_sys->ic->start_time * 1000000 / AV_TIME_BASE; msg_Dbg( p_demux, "AVFormat(%s %s) supported stream", AVPROVIDER(LIBAVFORMAT), LIBAVFORMAT_IDENT ); msg_Dbg( p_demux, " - format = %s (%s)", p_sys->fmt->name, p_sys->fmt->long_name ); msg_Dbg( p_demux, " - start time = %"PRId64, i_start_time ); msg_Dbg( p_demux, " - duration = %"PRId64, ( p_sys->ic->duration != (int64_t)AV_NOPTS_VALUE ) ? p_sys->ic->duration * 1000000 / AV_TIME_BASE : -1 ); if( p_sys->ic->nb_chapters > 0 ) { p_sys->p_title = vlc_input_title_New(); p_sys->p_title->i_length = p_sys->ic->duration * 1000000 / AV_TIME_BASE; } for( unsigned i = 0; i < p_sys->ic->nb_chapters; i++ ) { seekpoint_t *s = vlc_seekpoint_New(); AVDictionaryEntry *title = av_dict_get( p_sys->ic->metadata, "title", NULL, 0); if( title && title->value ) { s->psz_name = strdup( title->value ); EnsureUTF8( s->psz_name ); msg_Dbg( p_demux, " - chapter %d: %s", i, s->psz_name ); } s->i_time_offset = p_sys->ic->chapters[i]->start * 1000000 * p_sys->ic->chapters[i]->time_base.num / p_sys->ic->chapters[i]->time_base.den - (i_start_time != -1 ? i_start_time : 0 ); TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s ); } ResetTime( p_demux, 0 ); return VLC_SUCCESS; }
/***************************************************************************** * Open: probe the packetizer and return score *****************************************************************************/ static int Open( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'h', '2', '6', '4') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'H', '2', '6', '4') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'V', 'S', 'S', 'H') && p_dec->fmt_in.i_codec != VLC_FOURCC( 'v', 's', 's', 'h') && ( p_dec->fmt_in.i_codec != VLC_FOURCC( 'a', 'v', 'c', '1') || p_dec->fmt_in.i_extra < 7 ) ) { return VLC_EGENERIC; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = malloc( sizeof(decoder_sys_t) ) ) == NULL ) { msg_Err( p_dec, "out of memory" ); return VLC_EGENERIC; } p_sys->i_state = STATE_NOSYNC; p_sys->i_offset = 0; p_sys->startcode[0] = 0; p_sys->startcode[1] = 0; p_sys->startcode[2] = 0; p_sys->startcode[3] = 1; p_sys->bytestream = block_BytestreamInit( p_dec ); p_sys->b_slice = VLC_FALSE; p_sys->p_frame = NULL; p_sys->i_dts = 0; p_sys->i_pts = 0; p_sys->i_flags = 0; p_sys->b_sps = VLC_FALSE; p_sys->i_nal_type = -1; p_sys->i_nal_ref_idc = -1; p_sys->i_idr_pic_id = -1; p_sys->i_frame_num = -1; /* Setup properties */ es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); p_dec->fmt_out.i_codec = VLC_FOURCC( 'h', '2', '6', '4' ); /* FIXME: FFMPEG isn't happy at all if you leave this */ if( p_dec->fmt_out.i_extra ) free( p_dec->fmt_out.p_extra ); p_dec->fmt_out.i_extra = 0; p_dec->fmt_out.p_extra = 0; if( p_dec->fmt_in.i_codec == VLC_FOURCC( 'a', 'v', 'c', '1' ) ) { uint8_t *p = &((uint8_t*)p_dec->fmt_in.p_extra)[4]; int i_sps, i_pps; int i; /* Parse avcC */ p_sys->i_avcC_length_size = 1 + ((*p++)&0x03); /* Read SPS */ i_sps = (*p++)&0x1f; for( i = 0; i < i_sps; i++ ) { int i_length = GetWBE( p ); block_t *p_sps = nal_get_annexeb( p_dec, p + 2, i_length ); ParseNALBlock( p_dec, p_sps ); p += 2 + i_length; } /* Read PPS */ i_pps = *p++; for( i = 0; i < i_pps; i++ ) { int i_length = GetWBE( p ); block_t *p_pps = nal_get_annexeb( p_dec, p + 2, i_length ); ParseNALBlock( p_dec, p_pps ); p += 2 + i_length; } msg_Dbg( p_dec, "avcC length size=%d sps=%d pps=%d", p_sys->i_avcC_length_size, i_sps, i_pps ); /* Set callback */ p_dec->pf_packetize = PacketizeAVC1; } else { /* Set callback */ p_dec->pf_packetize = Packetize; } return VLC_SUCCESS; }
/***************************************************************************** * Decode: *****************************************************************************/ static int Decode( decoder_t *p_dec, block_t *p_block ) { subpicture_t *p_spu = NULL; if( p_block == NULL ) /* No Drain */ return VLCDEC_SUCCESS; if( ( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) ) || p_block->i_buffer < sizeof(uint16_t) ) { block_Release( p_block ); return VLCDEC_SUCCESS; } uint8_t *p_buf = p_block->p_buffer; /* Read our raw string and create the styled segment for HTML */ uint16_t i_psz_bytelength = GetWBE( p_buf ); const uint8_t *p_pszstart = p_block->p_buffer + sizeof(uint16_t); char *psz_subtitle; if ( i_psz_bytelength > 2 && ( !memcmp( p_pszstart, "\xFE\xFF", 2 ) || !memcmp( p_pszstart, "\xFF\xFE", 2 ) ) ) { psz_subtitle = FromCharset( "UTF-16", p_pszstart, i_psz_bytelength ); if ( !psz_subtitle ) return VLCDEC_SUCCESS; } else { psz_subtitle = malloc( i_psz_bytelength + 1 ); if ( !psz_subtitle ) return VLCDEC_SUCCESS; memcpy( psz_subtitle, p_pszstart, i_psz_bytelength ); psz_subtitle[ i_psz_bytelength ] = '\0'; } p_buf += i_psz_bytelength + sizeof(uint16_t); for( uint16_t i=0; i < i_psz_bytelength; i++ ) if ( psz_subtitle[i] == '\r' ) psz_subtitle[i] = '\n'; tx3g_segment_t *p_segment3g = tx3g_segment_New( psz_subtitle ); p_segment3g->i_size = str8len( psz_subtitle ); if ( p_dec->fmt_in.subs.p_style ) p_segment3g->s->style = text_style_Duplicate( p_dec->fmt_in.subs.p_style ); free( psz_subtitle ); if ( !p_segment3g->s->psz_text ) { text_segment_Delete( p_segment3g->s ); free( p_segment3g ); return VLCDEC_SUCCESS; } /* Create the subpicture unit */ p_spu = decoder_NewSubpictureText( p_dec ); if( !p_spu ) { text_segment_Delete( p_segment3g->s ); free( p_segment3g ); return VLCDEC_SUCCESS; } subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys; /* Parse our styles */ while( (size_t)(p_buf - p_block->p_buffer) + 8 < p_block->i_buffer ) { uint32_t i_atomsize = GetDWBE( p_buf ); vlc_fourcc_t i_atomtype = VLC_FOURCC(p_buf[4],p_buf[5],p_buf[6],p_buf[7]); p_buf += 8; switch( i_atomtype ) { case VLC_FOURCC('s','t','y','l'): { if ( (size_t)(p_buf - p_block->p_buffer) < 14 ) break; uint16_t i_nbrecords = GetWBE(p_buf); uint16_t i_cur_record = 0; p_buf += 2; while( i_cur_record++ < i_nbrecords ) { if ( (size_t)(p_buf - p_block->p_buffer) < 12 ) break; uint16_t i_start = __MIN( GetWBE(p_buf), i_psz_bytelength - 1 ); uint16_t i_end = __MIN( GetWBE(p_buf + 2), i_psz_bytelength - 1 ); text_style_t style; memset( &style, 0, sizeof(text_style_t) ); style.i_style_flags = ConvertFlags( p_buf[6] ); style.i_font_size = p_buf[7]; style.i_font_color = GetDWBE(p_buf+8) >> 8;// RGBA -> RGB style.i_font_alpha = GetDWBE(p_buf+8) & 0xFF; style.i_features = STYLE_HAS_FONT_COLOR | STYLE_HAS_FONT_ALPHA; ApplySegmentStyle( &p_segment3g, i_start, i_end, &style ); if ( i_nbrecords == 1 ) { if ( p_buf[6] ) { if( (p_spu_sys->p_default_style->i_style_flags = ConvertFlags( p_buf[6] )) ) p_spu_sys->p_default_style->i_features |= STYLE_HAS_FLAGS; } p_spu_sys->p_default_style->i_font_size = p_buf[7]; p_spu_sys->p_default_style->i_font_color = GetDWBE(p_buf+8) >> 8;// RGBA -> ARGB p_spu_sys->p_default_style->i_font_alpha = (GetDWBE(p_buf+8) & 0xFF) << 24; p_spu_sys->p_default_style->i_features |= (STYLE_HAS_FONT_COLOR | STYLE_HAS_FONT_ALPHA); } p_buf += 12; } } break; case VLC_FOURCC('d','r','p','o'): if ( (size_t)(p_buf - p_block->p_buffer) < 4 ) break; p_spu_sys->p_default_style->i_shadow_width = __MAX( GetWBE(p_buf), GetWBE(p_buf+2) ); break; case VLC_FOURCC('d','r','p','t'): if ( (size_t)(p_buf - p_block->p_buffer) < 2 ) break; p_spu_sys->p_default_style->i_shadow_alpha = GetWBE(p_buf); p_spu_sys->p_default_style->i_features |= STYLE_HAS_SHADOW_ALPHA; break; default: break; } p_buf += i_atomsize; } p_spu->i_start = p_block->i_pts; p_spu->i_stop = p_block->i_pts + p_block->i_length; p_spu->b_ephemer = (p_block->i_length == 0); p_spu->b_absolute = false; p_spu_sys->region.inner_align = SUBPICTURE_ALIGN_BOTTOM; FontSizeConvert( p_dec->fmt_in.subs.p_style, p_spu_sys->p_default_style ); /* Unwrap */ text_segment_t *p_text_segments = p_segment3g->s; text_segment_t *p_cur = p_text_segments; while( p_segment3g ) { FontSizeConvert( p_dec->fmt_in.subs.p_style, p_segment3g->s->style ); tx3g_segment_t * p_old = p_segment3g; p_segment3g = p_segment3g->p_next3g; free( p_old ); if( p_segment3g ) p_cur->p_next = p_segment3g->s; p_cur = p_cur->p_next; } p_spu_sys->region.p_segments = p_text_segments; block_Release( p_block ); decoder_QueueSub( p_dec, p_spu ); return VLCDEC_SUCCESS; }
/***************************************************************************** * OpenVideo: *****************************************************************************/ static int OpenVideo( decoder_t *p_dec ) { #ifndef WIN32 decoder_sys_t *p_sys = malloc( sizeof( decoder_sys_t ) ); if( !p_sys ) return VLC_ENOMEM; long i_result; ComponentDescription desc; Component prev; ComponentResult cres; ImageSubCodecDecompressCapabilities icap; /* for ImageCodecInitialize() */ CodecInfo cinfo; /* for ImageCodecGetCodecInfo() */ ImageDescription *id; char fcc[4]; int i_vide = p_dec->fmt_in.i_extra; uint8_t *p_vide = p_dec->fmt_in.p_extra; p_dec->p_sys = p_sys; p_dec->pf_decode_video = DecodeVideo; p_sys->i_late = 0; if( i_vide <= 0 ) { msg_Err( p_dec, "missing extra info" ); free( p_sys ); return VLC_EGENERIC; } if( p_dec->fmt_in.i_original_fourcc ) memcpy( fcc, &p_dec->fmt_in.i_original_fourcc, 4 ); else memcpy( fcc, &p_dec->fmt_in.i_codec, 4 ); msg_Dbg( p_dec, "quicktime_video %4.4s %dx%d", fcc, p_dec->fmt_in.video.i_width, p_dec->fmt_in.video.i_height ); /* get lock, avoid segfault */ vlc_mutex_lock( &qt_mutex ); #ifdef __APPLE__ EnterMovies(); #endif if( QTVideoInit( p_dec ) ) { msg_Err( p_dec, "cannot initialize QT"); goto exit_error; } #ifndef __APPLE__ if( ( i_result = p_sys->InitializeQTML( 6 + 16 ) ) ) { msg_Dbg( p_dec, "error on InitializeQTML = %d", (int)i_result ); goto exit_error; } #endif /* init ComponentDescription */ memset( &desc, 0, sizeof( ComponentDescription ) ); desc.componentType = FCC( 'i', 'm', 'd', 'c' ); desc.componentSubType = FCC( fcc[0], fcc[1], fcc[2], fcc[3] ); desc.componentManufacturer = 0; desc.componentFlags = 0; desc.componentFlagsMask = 0; if( !( prev = p_sys->FindNextComponent( NULL, &desc ) ) ) { msg_Err( p_dec, "cannot find requested component" ); goto exit_error; } msg_Dbg( p_dec, "component id=0x%p", prev ); p_sys->ci = p_sys->OpenComponent( prev ); msg_Dbg( p_dec, "component instance p=0x%p", p_sys->ci ); memset( &icap, 0, sizeof( ImageSubCodecDecompressCapabilities ) ); cres = p_sys->ImageCodecInitialize( p_sys->ci, &icap ); msg_Dbg( p_dec, "ImageCodecInitialize->0x%X size=%d (%d)", (int)cres, (int)icap.recordSize, (int)icap.decompressRecordSize); memset( &cinfo, 0, sizeof( CodecInfo ) ); cres = p_sys->ImageCodecGetCodecInfo( p_sys->ci, &cinfo ); msg_Dbg( p_dec, "Flags: compr: 0x%x decomp: 0x%x format: 0x%x", (unsigned int)cinfo.compressFlags, (unsigned int)cinfo.decompressFlags, (unsigned int)cinfo.formatFlags ); msg_Dbg( p_dec, "quicktime_video: Codec name: %.*s", ((unsigned char*)&cinfo.typeName)[0], ((unsigned char*)&cinfo.typeName)+1 ); /* make a yuy2 gworld */ p_sys->OutBufferRect.top = 0; p_sys->OutBufferRect.left = 0; p_sys->OutBufferRect.right = p_dec->fmt_in.video.i_width; p_sys->OutBufferRect.bottom = p_dec->fmt_in.video.i_height; /* codec data FIXME use codec not SVQ3 */ msg_Dbg( p_dec, "vide = %d", i_vide ); id = malloc( sizeof( ImageDescription ) + ( i_vide - 70 ) ); if( !id ) goto exit_error; id->idSize = sizeof( ImageDescription ) + ( i_vide - 70 ); id->cType = FCC( fcc[0], fcc[1], fcc[2], fcc[3] ); id->version = GetWBE ( p_vide + 0 ); id->revisionLevel = GetWBE ( p_vide + 2 ); id->vendor = GetDWBE( p_vide + 4 ); id->temporalQuality = GetDWBE( p_vide + 8 ); id->spatialQuality = GetDWBE( p_vide + 12 ); id->width = GetWBE ( p_vide + 16 ); id->height = GetWBE ( p_vide + 18 ); id->hRes = GetDWBE( p_vide + 20 ); id->vRes = GetDWBE( p_vide + 24 ); id->dataSize = GetDWBE( p_vide + 28 ); id->frameCount = GetWBE ( p_vide + 32 ); memcpy( &id->name, p_vide + 34, 32 ); id->depth = GetWBE ( p_vide + 66 ); id->clutID = GetWBE ( p_vide + 68 ); if( i_vide > 70 ) { memcpy( ((char*)&id->clutID) + 2, p_vide + 70, i_vide - 70 ); } msg_Dbg( p_dec, "idSize=%d ver=%d rev=%d vendor=%d tempQ=%d " "spaQ=%d w=%d h=%d dpi=%d%d dataSize=%d depth=%d frameCount=%d clutID=%d", (int)id->idSize, id->version, id->revisionLevel, (int)id->vendor, (int)id->temporalQuality, (int)id->spatialQuality, (int)id->width, (int)id->height, (int)id->hRes, (int)id->vRes, (int)id->dataSize, id->depth, id->frameCount, id->clutID ); p_sys->framedescHandle = (ImageDescriptionHandle) NewHandleClear( id->idSize ); memcpy( *p_sys->framedescHandle, id, id->idSize ); if( p_dec->fmt_in.video.i_width != 0 && p_dec->fmt_in.video.i_height != 0) p_sys->plane = malloc( p_dec->fmt_in.video.i_width * p_dec->fmt_in.video.i_height * 3 ); if( !p_sys->plane ) goto exit_error; i_result = p_sys->QTNewGWorldFromPtr( &p_sys->OutBufferGWorld, /*pixel format of new GWorld==YUY2 */ kYUVSPixelFormat, /* we should benchmark if yvu9 is * faster for svq3, too */ &p_sys->OutBufferRect, 0, 0, 0, p_sys->plane, p_dec->fmt_in.video.i_width * 2 ); msg_Dbg( p_dec, "NewGWorldFromPtr returned:%ld", 65536 - ( i_result&0xffff ) ); memset( &p_sys->decpar, 0, sizeof( CodecDecompressParams ) ); p_sys->decpar.imageDescription = p_sys->framedescHandle; p_sys->decpar.startLine = 0; p_sys->decpar.stopLine = ( **p_sys->framedescHandle ).height; p_sys->decpar.frameNumber = 1; p_sys->decpar.matrixFlags = 0; p_sys->decpar.matrixType = 0; p_sys->decpar.matrix = 0; p_sys->decpar.capabilities = &p_sys->codeccap; p_sys->decpar.accuracy = codecNormalQuality; p_sys->decpar.srcRect = p_sys->OutBufferRect; p_sys->decpar.transferMode = srcCopy; p_sys->decpar.dstPixMap = **p_sys->GetGWorldPixMap( p_sys->OutBufferGWorld );/*destPixmap; */ cres = p_sys->ImageCodecPreDecompress( p_sys->ci, &p_sys->decpar ); msg_Dbg( p_dec, "quicktime_video: ImageCodecPreDecompress cres=0x%X", (int)cres ); es_format_Init( &p_dec->fmt_out, VIDEO_ES, VLC_CODEC_YUYV); p_dec->fmt_out.video.i_width = p_dec->fmt_in.video.i_width; p_dec->fmt_out.video.i_height= p_dec->fmt_in.video.i_height; p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * p_dec->fmt_in.video.i_width / p_dec->fmt_in.video.i_height; vlc_mutex_unlock( &qt_mutex ); return VLC_SUCCESS; exit_error: #ifdef LOADER Restore_LDT_Keeper( p_sys->ldt_fs ); #endif vlc_mutex_unlock( &qt_mutex ); #else VLC_UNUSED( p_dec ); #endif /* !WIN32 */ return VLC_EGENERIC; }
/* ParseIDU: parse an Independent Decoding Unit */ static block_t *ParseIDU( decoder_t *p_dec, bool *pb_used_ts, block_t *p_frag ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_pic; const idu_type_t idu = (const idu_type_t)(p_frag->p_buffer[3]); // sunqueen modify *pb_used_ts = false; if( !p_sys->b_sequence_header && idu != IDU_TYPE_SEQUENCE_HEADER ) { msg_Warn( p_dec, "waiting for sequence header" ); block_Release( p_frag ); return NULL; } if( p_sys->b_sequence_header && !p_sys->b_entry_point && idu != IDU_TYPE_ENTRY_POINT ) { msg_Warn( p_dec, "waiting for entry point" ); block_Release( p_frag ); return NULL; } /* TODO we do not gather ENTRY_POINT and SEQUENCE_DATA user data * But It should not be a problem for decoder */ /* Do we have completed a frame */ p_pic = NULL; if( p_sys->b_frame && idu != IDU_TYPE_FRAME_USER_DATA && idu != IDU_TYPE_FIELD && idu != IDU_TYPE_FIELD_USER_DATA && idu != IDU_TYPE_SLICE && idu != IDU_TYPE_SLICE_USER_DATA && idu != IDU_TYPE_END_OF_SEQUENCE ) { /* Prepend SH and EP on I */ if( p_sys->p_frame->i_flags & BLOCK_FLAG_TYPE_I ) { block_t *p_list = block_Duplicate( p_sys->sh.p_sh ); block_ChainAppend( &p_list, block_Duplicate( p_sys->ep.p_ep ) ); block_ChainAppend( &p_list, p_sys->p_frame ); p_list->i_flags = p_sys->p_frame->i_flags; p_sys->p_frame = p_list; } /* */ p_pic = block_ChainGather( p_sys->p_frame ); p_pic->i_dts = p_sys->i_frame_dts; p_pic->i_pts = p_sys->i_frame_pts; /* */ if( p_pic->i_dts > VLC_TS_INVALID ) p_sys->i_interpolated_dts = p_pic->i_dts; /* We can interpolate dts/pts only if we have a frame rate */ if( p_dec->fmt_out.video.i_frame_rate != 0 && p_dec->fmt_out.video.i_frame_rate_base != 0 ) { if( p_sys->i_interpolated_dts > VLC_TS_INVALID ) p_sys->i_interpolated_dts += INT64_C(1000000) * p_dec->fmt_out.video.i_frame_rate_base / p_dec->fmt_out.video.i_frame_rate; //msg_Dbg( p_dec, "-------------- XXX0 dts=%"PRId64" pts=%"PRId64" interpolated=%"PRId64, // p_pic->i_dts, p_pic->i_pts, p_sys->i_interpolated_dts ); if( p_pic->i_dts <= VLC_TS_INVALID ) p_pic->i_dts = p_sys->i_interpolated_dts; if( p_pic->i_pts <= VLC_TS_INVALID ) { if( !p_sys->sh.b_has_bframe || (p_pic->i_flags & BLOCK_FLAG_TYPE_B ) ) p_pic->i_pts = p_pic->i_dts; /* TODO compute pts for other case */ } } //msg_Dbg( p_dec, "-------------- dts=%"PRId64" pts=%"PRId64, p_pic->i_dts, p_pic->i_pts ); /* Reset context */ p_sys->b_frame = false; p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; p_sys->p_frame = NULL; p_sys->pp_last = &p_sys->p_frame; } /* */ if( p_sys->i_frame_dts <= VLC_TS_INVALID && p_sys->i_frame_pts <= VLC_TS_INVALID ) { p_sys->i_frame_dts = p_frag->i_dts; p_sys->i_frame_pts = p_frag->i_pts; *pb_used_ts = true; } /* We will add back SH and EP on I frames */ block_t *p_release = NULL; if( idu != IDU_TYPE_SEQUENCE_HEADER && idu != IDU_TYPE_ENTRY_POINT ) block_ChainLastAppend( &p_sys->pp_last, p_frag ); else p_release = p_frag; /* Parse IDU */ if( idu == IDU_TYPE_SEQUENCE_HEADER ) { es_format_t *p_es = &p_dec->fmt_out; bs_t s; int i_profile; uint8_t ridu[32]; int i_ridu = sizeof(ridu); /* */ if( p_sys->sh.p_sh ) block_Release( p_sys->sh.p_sh ); p_sys->sh.p_sh = block_Duplicate( p_frag ); /* Extract the raw IDU */ DecodeRIDU( ridu, &i_ridu, &p_frag->p_buffer[4], p_frag->i_buffer - 4 ); /* Auto detect VC-1_SPMP_PESpacket_PayloadFormatHeader (SMPTE RP 227) for simple/main profile * TODO find a test case and valid it */ if( i_ridu > 4 && (ridu[0]&0x80) == 0 ) /* for advanced profile, the first bit is 1 */ { video_format_t *p_v = &p_dec->fmt_in.video; const size_t i_potential_width = GetWBE( &ridu[0] ); const size_t i_potential_height = GetWBE( &ridu[2] ); if( i_potential_width >= 2 && i_potential_width <= 8192 && i_potential_height >= 2 && i_potential_height <= 8192 ) { if( ( p_v->i_width <= 0 && p_v->i_height <= 0 ) || ( p_v->i_width == i_potential_width && p_v->i_height == i_potential_height ) ) { static const uint8_t startcode[4] = { 0x00, 0x00, 0x01, IDU_TYPE_SEQUENCE_HEADER }; p_es->video.i_width = i_potential_width; p_es->video.i_height = i_potential_height; /* Remove it */ p_frag->p_buffer += 4; p_frag->i_buffer -= 4; memcpy( p_frag->p_buffer, startcode, sizeof(startcode) ); } } } /* Parse it */ bs_init( &s, ridu, i_ridu ); i_profile = bs_read( &s, 2 ); if( i_profile == 3 ) { const int i_level = bs_read( &s, 3 ); /* Advanced profile */ p_sys->sh.b_advanced_profile = true; p_sys->sh.b_range_reduction = false; p_sys->sh.b_has_bframe = true; bs_skip( &s, 2+3+5+1 ); // chroma format + frame rate Q + bit rate Q + postprocflag p_es->video.i_width = 2*bs_read( &s, 12 )+2; p_es->video.i_height = 2*bs_read( &s, 12 )+2; if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "found sequence header for advanced profile level L%d resolution %dx%d", i_level, p_es->video.i_width, p_es->video.i_height); bs_skip( &s, 1 );// pulldown p_sys->sh.b_interlaced = bs_read( &s, 1 ); bs_skip( &s, 1 );// frame counter p_sys->sh.b_frame_interpolation = bs_read( &s, 1 ); bs_skip( &s, 1 ); // Reserved bs_skip( &s, 1 ); // Psf if( bs_read( &s, 1 ) ) /* Display extension */ { const int i_display_width = bs_read( &s, 14 )+1; const int i_display_height = bs_read( &s, 14 )+1; p_es->video.i_sar_num = i_display_width * p_es->video.i_height; p_es->video.i_sar_den = i_display_height * p_es->video.i_width; if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "display size %dx%d", i_display_width, i_display_height ); if( bs_read( &s, 1 ) ) /* Pixel aspect ratio (PAR/SAR) */ { static const int p_ar[16][2] = { { 0, 0}, { 1, 1}, {12,11}, {10,11}, {16,11}, {40,33}, {24,11}, {20,11}, {32,11}, {80,33}, {18,11}, {15,11}, {64,33}, {160,99},{ 0, 0}, { 0, 0} }; int i_ar = bs_read( &s, 4 ); unsigned i_ar_w, i_ar_h; if( i_ar == 15 ) { i_ar_w = bs_read( &s, 8 ); i_ar_h = bs_read( &s, 8 ); } else { i_ar_w = p_ar[i_ar][0]; i_ar_h = p_ar[i_ar][1]; } vlc_ureduce( &i_ar_w, &i_ar_h, i_ar_w, i_ar_h, 0 ); if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "aspect ratio %d:%d", i_ar_w, i_ar_h ); } } if( bs_read( &s, 1 ) ) /* Frame rate */ { int i_fps_num = 0; int i_fps_den = 0; if( bs_read( &s, 1 ) ) { i_fps_num = bs_read( &s, 16 )+1; i_fps_den = 32; } else { const int i_nr = bs_read( &s, 8 ); const int i_dn = bs_read( &s, 4 ); switch( i_nr ) { case 1: i_fps_num = 24000; break; case 2: i_fps_num = 25000; break; case 3: i_fps_num = 30000; break; case 4: i_fps_num = 50000; break; case 5: i_fps_num = 60000; break; case 6: i_fps_num = 48000; break; case 7: i_fps_num = 72000; break; } switch( i_dn ) { case 1: i_fps_den = 1000; break; case 2: i_fps_den = 1001; break; } } if( i_fps_num != 0 && i_fps_den != 0 ) vlc_ureduce( &p_es->video.i_frame_rate, &p_es->video.i_frame_rate_base, i_fps_num, i_fps_den, 0 ); if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "frame rate %d/%d", p_es->video.i_frame_rate, p_es->video.i_frame_rate_base ); } } else { /* Simple and main profile */ p_sys->sh.b_advanced_profile = false; p_sys->sh.b_interlaced = false; if( !p_sys->b_sequence_header ) msg_Dbg( p_dec, "found sequence header for %s profile", i_profile == 0 ? "simple" : "main" ); bs_skip( &s, 2+3+5+1+1+ // reserved + frame rate Q + bit rate Q + loop filter + reserved 1+1+1+1+2+ // multiresolution + reserved + fast uv mc + extended mv + dquant 1+1+1+1 ); // variable size transform + reserved + overlap + sync marker p_sys->sh.b_range_reduction = bs_read( &s, 1 ); if( bs_read( &s, 3 ) > 0 ) p_sys->sh.b_has_bframe = true; else p_sys->sh.b_has_bframe = false; bs_skip( &s, 2 ); // quantizer p_sys->sh.b_frame_interpolation = bs_read( &s, 1 ); } p_sys->b_sequence_header = true; BuildExtraData( p_dec ); } else if( idu == IDU_TYPE_ENTRY_POINT ) { if( p_sys->ep.p_ep ) block_Release( p_sys->ep.p_ep ); p_sys->ep.p_ep = block_Duplicate( p_frag ); if( !p_sys->b_entry_point ) msg_Dbg( p_dec, "found entry point" ); p_sys->b_entry_point = true; BuildExtraData( p_dec ); } else if( idu == IDU_TYPE_FRAME ) { bs_t s; uint8_t ridu[8]; int i_ridu = sizeof(ridu); /* Extract the raw IDU */ DecodeRIDU( ridu, &i_ridu, &p_frag->p_buffer[4], p_frag->i_buffer - 4 ); /* Parse it + interpolate pts/dts if possible */ bs_init( &s, ridu, i_ridu ); if( p_sys->sh.b_advanced_profile ) { int i_fcm = 0; if( p_sys->sh.b_interlaced ) { if( bs_read( &s, 1 ) ) { if( bs_read( &s, 1 ) ) i_fcm = 1; /* interlaced field */ else i_fcm = 2; /* interlaced frame */ } } if( i_fcm == 1 ) /*interlaced field */ { /* XXX for mixed I/P we should check reference usage before marking them I (too much work) */ switch( bs_read( &s, 3 ) ) { case 0: /* II */ case 1: /* IP */ case 2: /* PI */ p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; break; case 3: /* PP */ p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_P; break; case 4: /* BB */ case 5: /* BBi */ case 6: /* BiB */ case 7: /* BiBi */ p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B; break; } } else { if( !bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_P; else if( !bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B; else if( !bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; else if( !bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B; /* Bi */ else p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_P; /* P Skip */ } } else { if( p_sys->sh.b_frame_interpolation ) bs_skip( &s, 1 ); // interpolate bs_skip( &s, 2 ); // frame count if( p_sys->sh.b_range_reduction ) bs_skip( &s, 1 ); // range reduction if( bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_P; else if( !p_sys->sh.b_has_bframe || bs_read( &s, 1 ) ) p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_I; else p_sys->p_frame->i_flags |= BLOCK_FLAG_TYPE_B; } p_sys->b_frame = true; } if( p_release ) block_Release( p_release ); return p_pic; }
void xiph_decode (demux_t *demux, void *data, block_t *block) { rtp_xiph_t *self = (rtp_xiph_t *)data; // sunqueen modify if (!data || block->i_buffer < 4) goto drop; /* 32-bits RTP header (§2.2) */ uint32_t ident = GetDWBE (block->p_buffer); block->i_buffer -= 4; block->p_buffer += 4; unsigned fragtype = (ident >> 6) & 3; unsigned datatype = (ident >> 4) & 3; unsigned pkts = (ident) & 15; ident >>= 8; /* RTP defragmentation */ if (self->block && (block->i_flags & BLOCK_FLAG_DISCONTINUITY)) { /* Screwed! discontinuity within a fragmented packet */ msg_Warn (demux, self->vorbis ? "discontinuity in fragmented Vorbis packet" : "discontinuity in fragmented Theora packet"); block_Release (self->block); self->block = NULL; } if (fragtype <= 1) { if (self->block) /* Invalid first fragment */ { block_Release (self->block); self->block = NULL; } } else { if (!self->block) goto drop; /* Invalid non-first fragment */ } if (fragtype > 0) { /* Fragment */ if (pkts > 0 || block->i_buffer < 2) goto drop; size_t fraglen = GetWBE (block->p_buffer); if (block->i_buffer < (fraglen + 2)) goto drop; /* Invalid payload length */ block->i_buffer = fraglen; if (fragtype == 1)/* Keep first fragment */ { block->i_buffer += 2; self->block = block; } else { /* Append non-first fragment */ size_t len = self->block->i_buffer; self->block = block_Realloc (self->block, 0, len + fraglen); if (!self->block) { block_Release (block); return; } memcpy (self->block->p_buffer + len, block->p_buffer + 2, fraglen); block_Release (block); } if (fragtype < 3) return; /* Non-last fragment */ /* Last fragment reached, process it */ block = self->block; self->block = NULL; SetWBE (block->p_buffer, block->i_buffer - 2); pkts = 1; } /* RTP payload packets processing */ while (pkts > 0) { if (block->i_buffer < 2) goto drop; size_t len = GetWBE (block->p_buffer); block->i_buffer -= 2; block->p_buffer += 2; if (block->i_buffer < len) goto drop; switch (datatype) { case 0: /* Raw payload */ { if (self->ident != ident) { msg_Warn (demux, self->vorbis ? "ignoring raw Vorbis payload without configuration" : "ignoring raw Theora payload without configuration"); break; } block_t *raw = block_Alloc (len); memcpy (raw->p_buffer, block->p_buffer, len); raw->i_pts = block->i_pts; /* FIXME: what about pkts > 1 */ codec_decode (demux, self->id, raw); break; } case 1: /* Packed configuration frame (§3.1.1) */ { if (self->ident == ident) break; /* Ignore config retransmission */ void *extv; ssize_t extc = xiph_header (&extv, block->p_buffer, len); if (extc < 0) break; es_format_t fmt; es_format_Init (&fmt, self->vorbis ? AUDIO_ES : VIDEO_ES, self->vorbis ? VLC_CODEC_VORBIS : VLC_CODEC_THEORA); fmt.p_extra = extv; fmt.i_extra = extc; codec_destroy (demux, self->id); msg_Dbg (demux, self->vorbis ? "Vorbis packed configuration received (%06"PRIx32")" : "Theora packed configuration received (%06"PRIx32")", ident); self->ident = ident; self->id = (es_out_id_t *)codec_init (demux, &fmt); // sunqueen modify break; } } block->i_buffer -= len; block->p_buffer += len; pkts--; } drop: block_Release (block); }
/***************************************************************************** * Open: check file and initializes structures *****************************************************************************/ static int Open (vlc_object_t * p_this) { demux_t *p_demux = (demux_t *)p_this; stream_t *stream = p_demux->s; demux_sys_t *p_sys; const uint8_t *peek; unsigned tracks, ppqn; bool multitrack; /* (Try to) parse the SMF header */ /* Header chunk always has 6 bytes payload */ if (stream_Peek (stream, &peek, 14) < 14) return VLC_EGENERIC; /* Skip RIFF MIDI header if present */ if (!memcmp (peek, "RIFF", 4) && !memcmp (peek + 8, "RMID", 4)) { uint32_t riff_len = GetDWLE (peek + 4); msg_Dbg (p_this, "detected RIFF MIDI file (%u bytes)", (unsigned)riff_len); if ((stream_Read (stream, NULL, 12) < 12)) return VLC_EGENERIC; /* Look for the RIFF data chunk */ for (;;) { char chnk_hdr[8]; uint32_t chnk_len; if ((riff_len < 8) || (stream_Read (stream, chnk_hdr, 8) < 8)) return VLC_EGENERIC; riff_len -= 8; chnk_len = GetDWLE (chnk_hdr + 4); if (riff_len < chnk_len) return VLC_EGENERIC; riff_len -= chnk_len; if (!memcmp (chnk_hdr, "data", 4)) break; /* found! */ if (stream_Read (stream, NULL, chnk_len) < (ssize_t)chnk_len) return VLC_EGENERIC; } /* Read real SMF header. Assume RIFF data chunk length is proper. */ if (stream_Peek (stream, &peek, 14) < 14) return VLC_EGENERIC; } if (memcmp (peek, "MThd\x00\x00\x00\x06", 8)) return VLC_EGENERIC; peek += 8; /* First word: SMF type */ switch (GetWBE (peek)) { case 0: multitrack = false; break; case 1: multitrack = true; break; default: /* We don't implement SMF2 (as do many) */ msg_Err (p_this, "unsupported SMF file type %u", GetWBE (peek)); return VLC_EGENERIC; } peek += 2; /* Second word: number of tracks */ tracks = GetWBE (peek); peek += 2; if (!multitrack && (tracks != 1)) { msg_Err (p_this, "invalid SMF type 0 file"); return VLC_EGENERIC; } msg_Dbg (p_this, "detected Standard MIDI File (type %u) with %u track(s)", multitrack, tracks); /* Third/last word: timing */ ppqn = GetWBE (peek); if (ppqn & 0x8000) { /* FIXME */ msg_Err (p_this, "SMPTE timestamps not implemented"); return VLC_EGENERIC; } else { msg_Dbg (p_this, " %u pulses per quarter note", ppqn); } p_sys = malloc (sizeof (*p_sys) + (sizeof (mtrk_t) * tracks)); if (p_sys == NULL) return VLC_ENOMEM; /* We've had a valid SMF header - now skip it*/ if (stream_Read (stream, NULL, 14) < 14) goto error; p_demux->pf_demux = Demux; p_demux->pf_control = Control; p_demux->p_sys = p_sys; /* Default SMF tempo is 120BPM, i.e. half a second per quarter note */ date_Init (&p_sys->pts, ppqn * 2, 1); date_Set (&p_sys->pts, 0); p_sys->pulse = 0; p_sys->ppqn = ppqn; p_sys->trackc = tracks; /* Prefetch track offsets */ for (unsigned i = 0; i < tracks; i++) { uint8_t head[8]; if (i > 0) { /* Seeking screws streaming up, but there is no way around this, * as SMF1 tracks are performed simultaneously. * Not a big deal as SMF1 are usually only a few kbytes anyway. */ if (stream_Seek (stream, p_sys->trackv[i-1].end)) { msg_Err (p_this, "cannot build SMF index (corrupted file?)"); goto error; } } for (;;) { if (stream_Read (stream, head, 8) < 8) { /* FIXME: don't give up if we have at least one valid track */ msg_Err (p_this, "incomplete SMF chunk, file is corrupted"); goto error; } if (memcmp (head, "MTrk", 4) == 0) break; msg_Dbg (p_this, "skipping unknown SMF chunk"); stream_Read (stream, NULL, GetDWBE (head + 4)); } p_sys->trackv[i].offset = stream_Tell (stream); p_sys->trackv[i].end = p_sys->trackv[i].offset + GetDWBE (head + 4); p_sys->trackv[i].next = 0; ReadDeltaTime (stream, p_sys->trackv + i); p_sys->trackv[i].running_event = 0xF6; /* Why 0xF6 (Tuning Calibration)? * Because it has zero bytes of data, so the parser will detect the * error if the first event uses running status. */ } es_format_t fmt; es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_MIDI); fmt.audio.i_channels = 2; fmt.audio.i_rate = 44100; /* dummy value */ p_sys->es = es_out_Add (p_demux->out, &fmt); return VLC_SUCCESS; error: free (p_sys); return VLC_EGENERIC; }
static int AobHeader( unsigned *pi_rate, unsigned *pi_channels, unsigned *pi_layout, unsigned *pi_bits, unsigned *pi_padding, aob_group_t g[2], const uint8_t *p_header ) { const unsigned i_header_size = GetWBE( &p_header[1] ); if( i_header_size + 3 < LPCM_AOB_HEADER_LEN ) return VLC_EGENERIC; *pi_padding = 3+i_header_size - LPCM_AOB_HEADER_LEN; const int i_index_size_g1 = (p_header[6] >> 4) & 0x0f; const int i_index_size_g2 = (p_header[6] ) & 0x0f; const int i_index_rate_g1 = (p_header[7] >> 4) & 0x0f; const int i_index_rate_g2 = (p_header[7] ) & 0x0f; const int i_assignment = p_header[9]; /* Validate */ if( i_index_size_g1 > 0x02 || ( i_index_size_g2 != 0x0f && i_index_size_g2 > 0x02 ) ) return VLC_EGENERIC; if( (i_index_rate_g1 & 0x07) > 0x02 || ( i_index_rate_g2 != 0x0f && (i_index_rate_g1 & 0x07) > 0x02 ) ) return VLC_EGENERIC; if( i_assignment > 20 ) return VLC_EGENERIC; /* */ *pi_bits = 16 + 4 * i_index_size_g1; if( i_index_rate_g1 & 0x08 ) *pi_rate = 44100 << (i_index_rate_g1 & 0x07); else *pi_rate = 48000 << (i_index_rate_g1 & 0x07); /* Group1 */ unsigned i_channels1 = 0; unsigned i_layout1 = 0; for( int i = 0; p_aob_group1[i_assignment][i] != 0; i++ ) { i_channels1++; i_layout1 |= p_aob_group1[i_assignment][i]; } /* Group2 */ unsigned i_channels2 = 0; unsigned i_layout2 = 0; if( i_index_size_g2 != 0x0f && i_index_rate_g2 != 0x0f ) { for( int i = 0; p_aob_group2[i_assignment][i] != 0; i++ ) { i_channels2++; i_layout2 |= p_aob_group2[i_assignment][i]; } assert( (i_layout1 & i_layout2) == 0 ); } /* It is enabled only when presents and compatible wih group1 */ const bool b_group2_used = i_index_size_g1 == i_index_size_g2 && i_index_rate_g1 == i_index_rate_g2; /* */ *pi_channels = i_channels1 + ( b_group2_used ? i_channels2 : 0 ); *pi_layout = i_layout1 | ( b_group2_used ? i_layout2 : 0 ); /* */ for( unsigned i = 0; i < 2; i++ ) { const unsigned *p_aob = i == 0 ? p_aob_group1[i_assignment] : p_aob_group2[i_assignment]; g[i].i_channels = i == 0 ? i_channels1 : i_channels2; g[i].b_used = i == 0 || b_group2_used; if( !g[i].b_used ) continue; for( unsigned j = 0; j < g[i].i_channels; j++ ) { g[i].pi_position[j] = 0; for( int k = 0; pi_vlc_chan_order_wg4[k] != 0; k++ ) { const unsigned i_channel = pi_vlc_chan_order_wg4[k]; if( i_channel == p_aob[j] ) break; if( (*pi_layout) & i_channel ) g[i].pi_position[j]++; } } } return VLC_SUCCESS; }
static void NITCallBack( scan_session_t *p_session, dvbpsi_nit_t *p_nit ) { vlc_object_t *p_obj = p_session->p_obj; msg_Dbg( p_obj, "NITCallBack" ); msg_Dbg( p_obj, "new NIT network_id=%d version=%d current_next=%d", p_nit->i_network_id, p_nit->i_version, p_nit->b_current_next ); /* */ if( p_session->p_nit && p_session->p_nit->b_current_next ) { dvbpsi_DeleteNIT( p_session->p_nit ); p_session->p_nit = NULL; } if( p_session->p_nit ) { dvbpsi_DeleteNIT( p_nit ); return; } /* */ p_session->p_nit = p_nit; dvbpsi_descriptor_t *p_dsc; for( p_dsc = p_nit->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next ) { if( p_dsc->i_tag == 0x40 ) { msg_Dbg( p_obj, " * network name descriptor" ); char str1[257]; memcpy( str1, p_dsc->p_data, p_dsc->i_length ); str1[p_dsc->i_length] = '\0'; msg_Dbg( p_obj, " * name %s", str1 ); } else if( p_dsc->i_tag == 0x4a ) { msg_Dbg( p_obj, " * linkage descriptor" ); uint16_t i_ts_id = GetWBE( &p_dsc->p_data[0] ); uint16_t i_on_id = GetWBE( &p_dsc->p_data[2] ); uint16_t i_service_id = GetWBE( &p_dsc->p_data[4] ); int i_linkage_type = p_dsc->p_data[6]; msg_Dbg( p_obj, " * ts_id %d", i_ts_id ); msg_Dbg( p_obj, " * on_id %d", i_on_id ); msg_Dbg( p_obj, " * service_id %d", i_service_id ); msg_Dbg( p_obj, " * linkage_type %d", i_linkage_type ); } else { msg_Dbg( p_obj, " * dsc 0x%x", p_dsc->i_tag ); } } dvbpsi_nit_ts_t *p_ts; for( p_ts = p_nit->p_first_ts; p_ts != NULL; p_ts = p_ts->p_next ) { msg_Dbg( p_obj, " * ts ts_id=0x%x original_id=0x%x", p_ts->i_ts_id, p_ts->i_orig_network_id ); uint32_t i_private_data_id = 0; dvbpsi_descriptor_t *p_dsc; for( p_dsc = p_ts->p_first_descriptor; p_dsc != NULL; p_dsc = p_dsc->p_next ) { if( p_dsc->i_tag == 0x41 ) { msg_Dbg( p_obj, " * service list descriptor" ); for( int i = 0; i < p_dsc->i_length/3; i++ ) { uint16_t i_service_id = GetWBE( &p_dsc->p_data[3*i+0] ); uint8_t i_service_type = p_dsc->p_data[3*i+2]; msg_Dbg( p_obj, " * service_id=%d type=%d", i_service_id, i_service_type ); } } else if( p_dsc->i_tag == 0x5a ) { dvbpsi_terr_deliv_sys_dr_t *p_t = dvbpsi_DecodeTerrDelivSysDr( p_dsc ); msg_Dbg( p_obj, " * terrestrial delivery system" ); msg_Dbg( p_obj, " * centre_frequency 0x%x", p_t->i_centre_frequency ); msg_Dbg( p_obj, " * bandwidth %d", 8 - p_t->i_bandwidth ); msg_Dbg( p_obj, " * constellation %d", p_t->i_constellation ); msg_Dbg( p_obj, " * hierarchy %d", p_t->i_hierarchy_information ); msg_Dbg( p_obj, " * code_rate hp %d lp %d", p_t->i_code_rate_hp_stream, p_t->i_code_rate_lp_stream ); msg_Dbg( p_obj, " * guard_interval %d", p_t->i_guard_interval ); msg_Dbg( p_obj, " * transmission_mode %d", p_t->i_transmission_mode ); msg_Dbg( p_obj, " * other_frequency_flag %d", p_t->i_other_frequency_flag ); } else if( p_dsc->i_tag == 0x5f ) { msg_Dbg( p_obj, " * private data specifier descriptor" ); i_private_data_id = GetDWBE( &p_dsc->p_data[0] ); msg_Dbg( p_obj, " * value 0x%8.8x", i_private_data_id ); } else if( i_private_data_id == 0x28 && p_dsc->i_tag == 0x83 ) { msg_Dbg( p_obj, " * logical channel descriptor (EICTA)" ); for( int i = 0; i < p_dsc->i_length/4; i++ ) { uint16_t i_service_id = GetWBE( &p_dsc->p_data[4*i+0] ); int i_channel_number = GetWBE( &p_dsc->p_data[4*i+2] ) & 0x3ff; msg_Dbg( p_obj, " * service_id=%d channel_number=%d", i_service_id, i_channel_number ); } } else { msg_Warn( p_obj, " * dsc 0x%x", p_dsc->i_tag ); } } } }