2001-07-22 17:18:56 +03:00
/*
2006-10-23 11:57:54 +03:00
* ASF compatible demuxer
2009-01-19 17:46:40 +02:00
* Copyright ( c ) 2000 , 2001 Fabrice Bellard
2001-07-22 17:18:56 +03:00
*
2006-10-07 18:30:46 +03:00
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
2002-05-26 01:34:32 +03:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 18:30:46 +03:00
* version 2.1 of the License , or ( at your option ) any later version .
2001-07-22 17:18:56 +03:00
*
2006-10-07 18:30:46 +03:00
* FFmpeg is distributed in the hope that it will be useful ,
2001-07-22 17:18:56 +03:00
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
2002-05-26 01:34:32 +03:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
2001-07-22 17:18:56 +03:00
*
2002-05-26 01:34:32 +03:00
* You should have received a copy of the GNU Lesser General Public
2006-10-07 18:30:46 +03:00
* License along with FFmpeg ; if not , write to the Free Software
2006-01-13 00:43:26 +02:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-07-22 17:18:56 +03:00
*/
2008-05-09 14:56:36 +03:00
2009-05-24 12:59:53 +03:00
//#define DEBUG
2011-05-19 14:31:05 +03:00
# include "libavutil/bswap.h"
2008-05-09 14:56:36 +03:00
# include "libavutil/common.h"
2009-05-12 15:35:46 +03:00
# include "libavutil/avstring.h"
2011-05-22 13:46:29 +03:00
# include "libavutil/dict.h"
2011-06-04 14:58:23 +03:00
# include "libavutil/mathematics.h"
2012-04-06 16:54:23 +03:00
# include "libavutil/opt.h"
2001-07-22 17:18:56 +03:00
# include "avformat.h"
2011-11-29 21:28:15 +03:00
# include "internal.h"
2011-03-14 21:38:59 +02:00
# include "avio_internal.h"
2012-06-21 23:17:43 +03:00
# include "id3v2.h"
2006-07-12 03:09:34 +03:00
# include "riff.h"
2004-03-05 23:34:30 +02:00
# include "asf.h"
2007-10-20 17:25:02 +03:00
# include "asfcrypt.h"
2009-05-12 15:35:46 +03:00
# include "avlanguage.h"
2001-07-22 17:18:56 +03:00
2011-02-08 22:46:47 +02:00
typedef struct {
2012-04-06 16:54:23 +03:00
const AVClass * class ;
2011-02-08 22:46:47 +02:00
int asfid2avid [ 128 ] ; ///< conversion table from asf ID 2 AVStream ID
ASFStream streams [ 128 ] ; ///< it's max number and it's not that big
uint32_t stream_bitrates [ 128 ] ; ///< max number of streams, bitrate for each (for streaming)
2011-02-09 22:55:53 +02:00
AVRational dar [ 128 ] ;
2011-02-08 22:46:47 +02:00
char stream_languages [ 128 ] [ 6 ] ; ///< max number of streams, language for each (RFC1766, e.g. en-US)
/* non streamed additonnal info */
/* packet filling */
int packet_size_left ;
/* only for reading */
uint64_t data_offset ; ///< beginning of the first data packet
uint64_t data_object_offset ; ///< data object offset (excl. GUID & size)
uint64_t data_object_size ; ///< size of the data object
int index_read ;
ASFMainHeader hdr ;
int packet_flags ;
int packet_property ;
int packet_timestamp ;
int packet_segsizetype ;
int packet_segments ;
int packet_seq ;
int packet_replic_size ;
int packet_key_frame ;
int packet_padsize ;
unsigned int packet_frag_offset ;
unsigned int packet_frag_size ;
int64_t packet_frag_timestamp ;
int packet_multi_size ;
int packet_obj_size ;
int packet_time_delta ;
int packet_time_start ;
int64_t packet_pos ;
int stream_index ;
ASFStream * asf_st ; ///< currently decoded stream
2012-04-06 16:54:23 +03:00
int no_resync_search ;
2011-02-08 22:46:47 +02:00
} ASFContext ;
2012-04-06 16:54:23 +03:00
static const AVOption options [ ] = {
{ " no_resync_search " , " Don't try to resynchronize by looking for a certain optional start code " , offsetof ( ASFContext , no_resync_search ) , AV_OPT_TYPE_INT , { . dbl = 0 } , 0 , 1 , AV_OPT_FLAG_DECODING_PARAM } ,
{ NULL } ,
} ;
static const AVClass asf_class = {
. class_name = " asf demuxer " ,
. item_name = av_default_item_name ,
. option = options ,
. version = LIBAVUTIL_VERSION_INT ,
} ;
2004-01-14 16:45:53 +02:00
# undef NDEBUG
# include <assert.h>
2010-06-24 18:10:06 +03:00
# define ASF_MAX_STREAMS 127
2012-08-11 20:44:33 +03:00
# define FRAME_HEADER_SIZE 16
// Fix Me! FRAME_HEADER_SIZE may be different. (17 is known to be too large)
2004-03-06 00:10:50 +02:00
2011-07-03 17:57:26 +03:00
# ifdef DEBUG
2009-03-18 16:03:40 +02:00
static const ff_asf_guid stream_bitrate_guid = { /* (http://get.to/sdp) */
2007-02-21 01:44:11 +02:00
0xce , 0x75 , 0xf8 , 0x7b , 0x8d , 0x46 , 0xd1 , 0x11 , 0x8d , 0x82 , 0x00 , 0x60 , 0x97 , 0xc9 , 0xa2 , 0xb2
} ;
2001-07-22 17:18:56 +03:00
2003-02-25 15:12:41 +02:00
# define PRINT_IF_GUID(g,cmp) \
2010-12-26 03:26:29 +02:00
if ( ! ff_guidcmp ( g , & cmp ) ) \
2011-01-29 18:46:18 +02:00
av_dlog ( NULL , " (GUID: %s) " , # cmp )
2003-02-25 15:12:41 +02:00
2009-03-18 16:03:40 +02:00
static void print_guid ( const ff_asf_guid * g )
2001-07-22 17:18:56 +03:00
{
int i ;
2009-02-26 18:17:17 +02:00
PRINT_IF_GUID ( g , ff_asf_header ) ;
else PRINT_IF_GUID ( g , ff_asf_file_header ) ;
else PRINT_IF_GUID ( g , ff_asf_stream_header ) ;
else PRINT_IF_GUID ( g , ff_asf_audio_stream ) ;
else PRINT_IF_GUID ( g , ff_asf_audio_conceal_none ) ;
else PRINT_IF_GUID ( g , ff_asf_video_stream ) ;
else PRINT_IF_GUID ( g , ff_asf_video_conceal_none ) ;
else PRINT_IF_GUID ( g , ff_asf_command_stream ) ;
else PRINT_IF_GUID ( g , ff_asf_comment_header ) ;
else PRINT_IF_GUID ( g , ff_asf_codec_comment_header ) ;
else PRINT_IF_GUID ( g , ff_asf_codec_comment1_header ) ;
else PRINT_IF_GUID ( g , ff_asf_data_header ) ;
2012-04-03 10:44:10 +03:00
else PRINT_IF_GUID ( g , ff_asf_simple_index_header ) ;
2009-02-26 18:17:17 +02:00
else PRINT_IF_GUID ( g , ff_asf_head1_guid ) ;
else PRINT_IF_GUID ( g , ff_asf_head2_guid ) ;
else PRINT_IF_GUID ( g , ff_asf_my_guid ) ;
else PRINT_IF_GUID ( g , ff_asf_ext_stream_header ) ;
else PRINT_IF_GUID ( g , ff_asf_extended_content_header ) ;
else PRINT_IF_GUID ( g , ff_asf_ext_stream_embed_stream_header ) ;
else PRINT_IF_GUID ( g , ff_asf_ext_stream_audio_stream ) ;
else PRINT_IF_GUID ( g , ff_asf_metadata_header ) ;
2010-03-08 15:13:18 +02:00
else PRINT_IF_GUID ( g , ff_asf_marker_header ) ;
2007-02-21 01:44:11 +02:00
else PRINT_IF_GUID ( g , stream_bitrate_guid ) ;
2009-05-12 15:35:46 +03:00
else PRINT_IF_GUID ( g , ff_asf_language_guid ) ;
2003-02-25 15:12:41 +02:00
else
2011-01-29 18:46:18 +02:00
av_dlog ( NULL , " (GUID: unknown) " ) ;
2007-01-21 22:06:19 +02:00
for ( i = 0 ; i < 16 ; i + + )
2011-01-29 18:46:18 +02:00
av_dlog ( NULL , " 0x%02x, " , ( * g ) [ i ] ) ;
av_dlog ( NULL , " } \n " ) ;
2001-07-22 17:18:56 +03:00
}
2006-02-12 04:24:37 +02:00
# undef PRINT_IF_GUID
2008-07-13 22:41:07 +03:00
# else
# define print_guid(g)
2001-07-22 17:18:56 +03:00
# endif
2002-05-20 19:31:13 +03:00
static int asf_probe ( AVProbeData * pd )
{
/* check file header */
2010-12-26 03:26:29 +02:00
if ( ! ff_guidcmp ( pd - > buf , & ff_asf_header ) )
2002-05-20 19:31:13 +03:00
return AVPROBE_SCORE_MAX ;
else
return 0 ;
}
2011-02-20 12:04:12 +02:00
static int get_value ( AVIOContext * pb , int type ) {
2007-02-01 01:32:01 +02:00
switch ( type ) {
2011-02-21 17:43:01 +02:00
case 2 : return avio_rl32 ( pb ) ;
case 3 : return avio_rl32 ( pb ) ;
case 4 : return avio_rl64 ( pb ) ;
case 5 : return avio_rl16 ( pb ) ;
2007-02-01 01:32:01 +02:00
default : return INT_MIN ;
}
}
2012-06-21 23:17:43 +03:00
/* MSDN claims that this should be "compatible with the ID3 frame, APIC",
* but in reality this is only loosely similar */
static int asf_read_picture ( AVFormatContext * s , int len )
{
AVPacket pkt = { 0 } ;
const CodecMime * mime = ff_id3v2_mime_tags ;
2012-08-05 12:11:04 +03:00
enum AVCodecID id = AV_CODEC_ID_NONE ;
2012-06-21 23:17:43 +03:00
char mimetype [ 64 ] ;
uint8_t * desc = NULL ;
ASFStream * ast = NULL ;
AVStream * st = NULL ;
int ret , type , picsize , desc_len ;
/* type + picsize + mime + desc */
if ( len < 1 + 4 + 2 + 2 ) {
av_log ( s , AV_LOG_ERROR , " Invalid attached picture size: %d. \n " , len ) ;
return AVERROR_INVALIDDATA ;
}
/* picture type */
type = avio_r8 ( s - > pb ) ;
len - - ;
if ( type > = FF_ARRAY_ELEMS ( ff_id3v2_picture_types ) | | type < 0 ) {
av_log ( s , AV_LOG_WARNING , " Unknown attached picture type: %d. \n " , type ) ;
type = 0 ;
}
/* picture data size */
picsize = avio_rl32 ( s - > pb ) ;
len - = 4 ;
/* picture MIME type */
len - = avio_get_str16le ( s - > pb , len , mimetype , sizeof ( mimetype ) ) ;
2012-08-05 12:11:04 +03:00
while ( mime - > id ! = AV_CODEC_ID_NONE ) {
2012-06-21 23:17:43 +03:00
if ( ! strncmp ( mime - > str , mimetype , sizeof ( mimetype ) ) ) {
id = mime - > id ;
break ;
}
mime + + ;
}
2012-08-05 12:11:04 +03:00
if ( id = = AV_CODEC_ID_NONE ) {
2012-06-21 23:17:43 +03:00
av_log ( s , AV_LOG_ERROR , " Unknown attached picture mimetype: %s. \n " ,
mimetype ) ;
return 0 ;
}
if ( picsize > = len ) {
av_log ( s , AV_LOG_ERROR , " Invalid attached picture data size: %d >= %d. \n " ,
picsize , len ) ;
return AVERROR_INVALIDDATA ;
}
/* picture description */
desc_len = ( len - picsize ) * 2 + 1 ;
desc = av_malloc ( desc_len ) ;
if ( ! desc )
return AVERROR ( ENOMEM ) ;
len - = avio_get_str16le ( s - > pb , len - picsize , desc , desc_len ) ;
ret = av_get_packet ( s - > pb , & pkt , picsize ) ;
if ( ret < 0 )
goto fail ;
st = avformat_new_stream ( s , NULL ) ;
ast = av_mallocz ( sizeof ( * ast ) ) ;
if ( ! st | | ! ast ) {
ret = AVERROR ( ENOMEM ) ;
goto fail ;
}
st - > priv_data = ast ;
st - > disposition | = AV_DISPOSITION_ATTACHED_PIC ;
st - > codec - > codec_type = AVMEDIA_TYPE_VIDEO ;
st - > codec - > codec_id = id ;
st - > attached_pic = pkt ;
st - > attached_pic . stream_index = st - > index ;
st - > attached_pic . flags | = AV_PKT_FLAG_KEY ;
if ( * desc )
av_dict_set ( & st - > metadata , " title " , desc , AV_DICT_DONT_STRDUP_VAL ) ;
else
av_freep ( & desc ) ;
av_dict_set ( & st - > metadata , " comment " , ff_id3v2_picture_types [ type ] , 0 ) ;
return 0 ;
fail :
av_freep ( & ast ) ;
av_freep ( & desc ) ;
av_free_packet ( & pkt ) ;
return ret ;
}
2009-02-04 00:12:06 +02:00
static void get_tag ( AVFormatContext * s , const char * key , int type , int len )
{
2009-12-13 22:27:29 +02:00
char * value ;
2011-03-03 21:11:45 +02:00
int64_t off = avio_tell ( s - > pb ) ;
2009-12-13 22:27:29 +02:00
2010-02-24 20:19:54 +02:00
if ( ( unsigned ) len > = ( UINT_MAX - 1 ) / 2 )
2009-12-13 22:27:29 +02:00
return ;
2010-02-24 20:19:54 +02:00
value = av_malloc ( 2 * len + 1 ) ;
2009-12-13 22:27:29 +02:00
if ( ! value )
2011-01-27 11:41:49 +02:00
goto finish ;
2009-12-13 22:27:29 +02:00
2010-02-24 09:34:12 +02:00
if ( type = = 0 ) { // UTF16-LE
2011-01-23 13:38:27 +02:00
avio_get_str16le ( s - > pb , len , value , 2 * len + 1 ) ;
2011-10-16 06:04:48 +03:00
} else if ( type = = - 1 ) { // ASCII
2011-11-14 02:53:50 +03:00
avio_read ( s - > pb , value , len ) ;
2011-10-16 06:04:48 +03:00
value [ len ] = 0 ;
2010-02-24 09:34:12 +02:00
} else if ( type > 1 & & type < = 5 ) { // boolean or DWORD or QWORD or WORD
2009-02-04 00:12:06 +02:00
uint64_t num = get_value ( s - > pb , type ) ;
2009-12-13 22:27:29 +02:00
snprintf ( value , len , " % " PRIu64 , num ) ;
2012-06-21 23:17:43 +03:00
} else if ( type = = 1 & & ! strcmp ( key , " WM/Picture " ) ) { // handle cover art
asf_read_picture ( s , len ) ;
goto finish ;
2009-02-04 00:12:06 +02:00
} else {
2010-02-24 09:33:18 +02:00
av_log ( s , AV_LOG_DEBUG , " Unsupported value type %d in tag %s. \n " , type , key ) ;
2011-01-27 11:41:49 +02:00
goto finish ;
2009-02-04 00:12:06 +02:00
}
2011-02-09 22:56:00 +02:00
if ( * value )
2011-05-22 13:46:29 +03:00
av_dict_set ( & s - > metadata , key , value , 0 ) ;
2011-01-27 11:41:49 +02:00
finish :
2010-02-24 20:19:54 +02:00
av_freep ( & value ) ;
2011-02-28 15:57:54 +02:00
avio_seek ( s - > pb , off + len , SEEK_SET ) ;
2009-02-04 00:12:06 +02:00
}
2011-02-09 22:55:55 +02:00
static int asf_read_file_properties ( AVFormatContext * s , int64_t size )
{
ASFContext * asf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:55 +02:00
ff_get_guid ( pb , & asf - > hdr . guid ) ;
2011-02-21 17:43:01 +02:00
asf - > hdr . file_size = avio_rl64 ( pb ) ;
asf - > hdr . create_time = avio_rl64 ( pb ) ;
avio_rl64 ( pb ) ; /* number of packets */
asf - > hdr . play_time = avio_rl64 ( pb ) ;
asf - > hdr . send_time = avio_rl64 ( pb ) ;
asf - > hdr . preroll = avio_rl32 ( pb ) ;
asf - > hdr . ignore = avio_rl32 ( pb ) ;
asf - > hdr . flags = avio_rl32 ( pb ) ;
asf - > hdr . min_pktsize = avio_rl32 ( pb ) ;
asf - > hdr . max_pktsize = avio_rl32 ( pb ) ;
2012-02-17 23:21:22 +03:00
if ( asf - > hdr . min_pktsize > = ( 1U < < 29 ) )
return AVERROR_INVALIDDATA ;
2011-02-21 17:43:01 +02:00
asf - > hdr . max_bitrate = avio_rl32 ( pb ) ;
2011-02-09 22:55:55 +02:00
s - > packet_size = asf - > hdr . max_pktsize ;
return 0 ;
}
2011-02-09 22:55:57 +02:00
static int asf_read_stream_properties ( AVFormatContext * s , int64_t size )
{
ASFContext * asf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:57 +02:00
AVStream * st ;
ASFStream * asf_st ;
ff_asf_guid g ;
enum AVMediaType type ;
int type_specific_size , sizeX ;
unsigned int tag1 ;
int64_t pos1 , pos2 , start_time ;
int test_for_ext_stream_audio , is_dvr_ms_audio = 0 ;
if ( s - > nb_streams = = ASF_MAX_STREAMS ) {
av_log ( s , AV_LOG_ERROR , " too many streams \n " ) ;
return AVERROR ( EINVAL ) ;
}
2011-03-03 21:11:45 +02:00
pos1 = avio_tell ( pb ) ;
2011-02-09 22:55:57 +02:00
2011-06-18 12:43:24 +03:00
st = avformat_new_stream ( s , NULL ) ;
2011-02-09 22:55:57 +02:00
if ( ! st )
return AVERROR ( ENOMEM ) ;
2011-11-29 21:28:15 +03:00
avpriv_set_pts_info ( st , 32 , 1 , 1000 ) ; /* 32 bit pts in ms */
2011-02-09 22:55:57 +02:00
asf_st = av_mallocz ( sizeof ( ASFStream ) ) ;
if ( ! asf_st )
return AVERROR ( ENOMEM ) ;
st - > priv_data = asf_st ;
start_time = asf - > hdr . preroll ;
asf_st - > stream_language_index = 128 ; // invalid stream index means no language info
if ( ! ( asf - > hdr . flags & 0x01 ) ) { // if we aren't streaming...
st - > duration = asf - > hdr . play_time /
( 10000000 / 1000 ) - start_time ;
}
ff_get_guid ( pb , & g ) ;
test_for_ext_stream_audio = 0 ;
if ( ! ff_guidcmp ( & g , & ff_asf_audio_stream ) ) {
type = AVMEDIA_TYPE_AUDIO ;
} else if ( ! ff_guidcmp ( & g , & ff_asf_video_stream ) ) {
type = AVMEDIA_TYPE_VIDEO ;
} else if ( ! ff_guidcmp ( & g , & ff_asf_jfif_media ) ) {
type = AVMEDIA_TYPE_VIDEO ;
2012-08-05 12:11:04 +03:00
st - > codec - > codec_id = AV_CODEC_ID_MJPEG ;
2011-02-09 22:55:57 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_command_stream ) ) {
type = AVMEDIA_TYPE_DATA ;
} else if ( ! ff_guidcmp ( & g , & ff_asf_ext_stream_embed_stream_header ) ) {
test_for_ext_stream_audio = 1 ;
type = AVMEDIA_TYPE_UNKNOWN ;
} else {
return - 1 ;
}
ff_get_guid ( pb , & g ) ;
2011-06-01 19:26:27 +03:00
avio_skip ( pb , 8 ) ; /* total_size */
2011-02-21 17:43:01 +02:00
type_specific_size = avio_rl32 ( pb ) ;
avio_rl32 ( pb ) ;
st - > id = avio_rl16 ( pb ) & 0x7f ; /* stream id */
2011-02-09 22:55:57 +02:00
// mapping of asf ID to AV stream ID;
asf - > asfid2avid [ st - > id ] = s - > nb_streams - 1 ;
2011-02-21 17:43:01 +02:00
avio_rl32 ( pb ) ;
2011-02-09 22:55:57 +02:00
if ( test_for_ext_stream_audio ) {
ff_get_guid ( pb , & g ) ;
if ( ! ff_guidcmp ( & g , & ff_asf_ext_stream_audio_stream ) ) {
type = AVMEDIA_TYPE_AUDIO ;
is_dvr_ms_audio = 1 ;
ff_get_guid ( pb , & g ) ;
2011-02-21 17:43:01 +02:00
avio_rl32 ( pb ) ;
avio_rl32 ( pb ) ;
avio_rl32 ( pb ) ;
2011-02-09 22:55:57 +02:00
ff_get_guid ( pb , & g ) ;
2011-02-21 17:43:01 +02:00
avio_rl32 ( pb ) ;
2011-02-09 22:55:57 +02:00
}
}
st - > codec - > codec_type = type ;
if ( type = = AVMEDIA_TYPE_AUDIO ) {
2011-04-12 18:44:20 +03:00
int ret = ff_get_wav_header ( pb , st - > codec , type_specific_size ) ;
if ( ret < 0 )
return ret ;
2011-02-09 22:55:57 +02:00
if ( is_dvr_ms_audio ) {
// codec_id and codec_tag are unreliable in dvr_ms
// files. Set them later by probing stream.
2011-03-04 02:12:17 +02:00
st - > request_probe = 1 ;
2011-02-09 22:55:57 +02:00
st - > codec - > codec_tag = 0 ;
}
2012-08-05 12:11:04 +03:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_AAC ) {
2011-02-09 22:55:57 +02:00
st - > need_parsing = AVSTREAM_PARSE_NONE ;
} else {
st - > need_parsing = AVSTREAM_PARSE_FULL ;
}
/* We have to init the frame size at some point .... */
2011-03-03 21:11:45 +02:00
pos2 = avio_tell ( pb ) ;
2011-02-09 22:55:57 +02:00
if ( size > = ( pos2 + 8 - pos1 + 24 ) ) {
2011-02-21 17:43:01 +02:00
asf_st - > ds_span = avio_r8 ( pb ) ;
asf_st - > ds_packet_size = avio_rl16 ( pb ) ;
asf_st - > ds_chunk_size = avio_rl16 ( pb ) ;
avio_rl16 ( pb ) ; //ds_data_size
avio_r8 ( pb ) ; //ds_silence_data
2011-02-09 22:55:57 +02:00
}
//printf("Descrambling: ps:%d cs:%d ds:%d s:%d sd:%d\n",
// asf_st->ds_packet_size, asf_st->ds_chunk_size,
// asf_st->ds_data_size, asf_st->ds_span, asf_st->ds_silence_data);
if ( asf_st - > ds_span > 1 ) {
if ( ! asf_st - > ds_chunk_size
| | ( asf_st - > ds_packet_size / asf_st - > ds_chunk_size < = 1 )
| | asf_st - > ds_packet_size % asf_st - > ds_chunk_size )
asf_st - > ds_span = 0 ; // disable descrambling
}
} else if ( type = = AVMEDIA_TYPE_VIDEO & &
2011-03-03 21:11:45 +02:00
size - ( avio_tell ( pb ) - pos1 + 24 ) > = 51 ) {
2011-02-21 17:43:01 +02:00
avio_rl32 ( pb ) ;
avio_rl32 ( pb ) ;
avio_r8 ( pb ) ;
avio_rl16 ( pb ) ; /* size */
sizeX = avio_rl32 ( pb ) ; /* size */
st - > codec - > width = avio_rl32 ( pb ) ;
st - > codec - > height = avio_rl32 ( pb ) ;
2011-02-09 22:55:57 +02:00
/* not available for asf */
2011-02-21 17:43:01 +02:00
avio_rl16 ( pb ) ; /* panes */
st - > codec - > bits_per_coded_sample = avio_rl16 ( pb ) ; /* depth */
tag1 = avio_rl32 ( pb ) ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 20 ) ;
2011-02-09 22:55:57 +02:00
// av_log(s, AV_LOG_DEBUG, "size:%d tsize:%d sizeX:%d\n", size, total_size, sizeX);
if ( sizeX > 40 ) {
st - > codec - > extradata_size = sizeX - 40 ;
st - > codec - > extradata = av_mallocz ( st - > codec - > extradata_size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2011-02-21 17:43:01 +02:00
avio_read ( pb , st - > codec - > extradata , st - > codec - > extradata_size ) ;
2011-02-09 22:55:57 +02:00
}
/* Extract palette from extradata if bpp <= 8 */
/* This code assumes that extradata contains only palette */
2011-10-30 20:02:42 +03:00
/* This is true for all paletted codecs implemented in libavcodec */
2011-02-09 22:55:57 +02:00
if ( st - > codec - > extradata_size & & ( st - > codec - > bits_per_coded_sample < = 8 ) ) {
# if HAVE_BIGENDIAN
2012-02-10 17:10:42 +03:00
int i ;
2011-02-09 22:55:57 +02:00
for ( i = 0 ; i < FFMIN ( st - > codec - > extradata_size , AVPALETTE_SIZE ) / 4 ; i + + )
2011-04-09 16:49:51 +03:00
asf_st - > palette [ i ] = av_bswap32 ( ( ( uint32_t * ) st - > codec - > extradata ) [ i ] ) ;
2011-02-09 22:55:57 +02:00
# else
2011-04-09 16:49:51 +03:00
memcpy ( asf_st - > palette , st - > codec - > extradata ,
FFMIN ( st - > codec - > extradata_size , AVPALETTE_SIZE ) ) ;
2011-02-09 22:55:57 +02:00
# endif
2011-04-09 16:49:51 +03:00
asf_st - > palette_changed = 1 ;
2011-02-09 22:55:57 +02:00
}
st - > codec - > codec_tag = tag1 ;
st - > codec - > codec_id = ff_codec_get_id ( ff_codec_bmp_tags , tag1 ) ;
if ( tag1 = = MKTAG ( ' D ' , ' V ' , ' R ' , ' ' ) ) {
st - > need_parsing = AVSTREAM_PARSE_FULL ;
// issue658 containse wrong w/h and MS even puts a fake seq header with wrong w/h in extradata while a correct one is in te stream. maximum lameness
st - > codec - > width =
st - > codec - > height = 0 ;
av_freep ( & st - > codec - > extradata ) ;
st - > codec - > extradata_size = 0 ;
}
2012-08-05 12:11:04 +03:00
if ( st - > codec - > codec_id = = AV_CODEC_ID_H264 )
2011-02-09 22:55:57 +02:00
st - > need_parsing = AVSTREAM_PARSE_FULL_ONCE ;
}
2011-03-03 21:11:45 +02:00
pos2 = avio_tell ( pb ) ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , size - ( pos2 - pos1 + 24 ) ) ;
2011-02-09 22:55:57 +02:00
return 0 ;
}
2011-02-09 22:55:55 +02:00
static int asf_read_ext_stream_properties ( AVFormatContext * s , int64_t size )
{
ASFContext * asf = s - > priv_data ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:55 +02:00
ff_asf_guid g ;
int ext_len , payload_ext_ct , stream_ct , i ;
2011-06-01 19:26:27 +03:00
uint32_t leak_rate , stream_num ;
2011-02-09 22:55:55 +02:00
unsigned int stream_languageid_index ;
2011-02-21 17:43:01 +02:00
avio_rl64 ( pb ) ; // starttime
avio_rl64 ( pb ) ; // endtime
leak_rate = avio_rl32 ( pb ) ; // leak-datarate
avio_rl32 ( pb ) ; // bucket-datasize
avio_rl32 ( pb ) ; // init-bucket-fullness
avio_rl32 ( pb ) ; // alt-leak-datarate
avio_rl32 ( pb ) ; // alt-bucket-datasize
avio_rl32 ( pb ) ; // alt-init-bucket-fullness
avio_rl32 ( pb ) ; // max-object-size
avio_rl32 ( pb ) ; // flags (reliable,seekable,no_cleanpoints?,resend-live-cleanpoints, rest of bits reserved)
stream_num = avio_rl16 ( pb ) ; // stream-num
stream_languageid_index = avio_rl16 ( pb ) ; // stream-language-id-index
2011-02-09 22:55:55 +02:00
if ( stream_num < 128 )
asf - > streams [ stream_num ] . stream_language_index = stream_languageid_index ;
2011-02-21 17:43:01 +02:00
avio_rl64 ( pb ) ; // avg frametime in 100ns units
stream_ct = avio_rl16 ( pb ) ; //stream-name-count
payload_ext_ct = avio_rl16 ( pb ) ; //payload-extension-system-count
2011-02-09 22:55:55 +02:00
if ( stream_num < 128 )
asf - > stream_bitrates [ stream_num ] = leak_rate ;
for ( i = 0 ; i < stream_ct ; i + + ) {
2011-02-21 17:43:01 +02:00
avio_rl16 ( pb ) ;
ext_len = avio_rl16 ( pb ) ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , ext_len ) ;
2011-02-09 22:55:55 +02:00
}
for ( i = 0 ; i < payload_ext_ct ; i + + ) {
ff_get_guid ( pb , & g ) ;
2011-06-01 19:26:27 +03:00
avio_skip ( pb , 2 ) ;
2011-02-21 17:43:01 +02:00
ext_len = avio_rl32 ( pb ) ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , ext_len ) ;
2011-02-09 22:55:55 +02:00
}
return 0 ;
}
static int asf_read_content_desc ( AVFormatContext * s , int64_t size )
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:55 +02:00
int len1 , len2 , len3 , len4 , len5 ;
2011-02-21 17:43:01 +02:00
len1 = avio_rl16 ( pb ) ;
len2 = avio_rl16 ( pb ) ;
len3 = avio_rl16 ( pb ) ;
len4 = avio_rl16 ( pb ) ;
len5 = avio_rl16 ( pb ) ;
2011-02-09 22:55:55 +02:00
get_tag ( s , " title " , 0 , len1 ) ;
get_tag ( s , " author " , 0 , len2 ) ;
get_tag ( s , " copyright " , 0 , len3 ) ;
get_tag ( s , " comment " , 0 , len4 ) ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , len5 ) ;
2011-02-09 22:55:55 +02:00
return 0 ;
}
static int asf_read_ext_content_desc ( AVFormatContext * s , int64_t size )
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:55 +02:00
ASFContext * asf = s - > priv_data ;
int desc_count , i , ret ;
2011-02-21 17:43:01 +02:00
desc_count = avio_rl16 ( pb ) ;
2011-02-09 22:55:55 +02:00
for ( i = 0 ; i < desc_count ; i + + ) {
int name_len , value_type , value_len ;
char name [ 1024 ] ;
2011-02-21 17:43:01 +02:00
name_len = avio_rl16 ( pb ) ;
2011-02-09 22:55:55 +02:00
if ( name_len % 2 ) // must be even, broken lavf versions wrote len-1
name_len + = 1 ;
if ( ( ret = avio_get_str16le ( pb , name_len , name , sizeof ( name ) ) ) < name_len )
2011-03-15 10:14:38 +02:00
avio_skip ( pb , name_len - ret ) ;
2011-02-21 17:43:01 +02:00
value_type = avio_rl16 ( pb ) ;
value_len = avio_rl16 ( pb ) ;
2011-02-09 22:55:55 +02:00
if ( ! value_type & & value_len % 2 )
value_len + = 1 ;
/**
* My sample has that stream set to 0 maybe that mean the container .
* Asf stream count start at 1. I am using 0 to the container value since it ' s unused
*/
if ( ! strcmp ( name , " AspectRatioX " ) ) {
asf - > dar [ 0 ] . num = get_value ( s - > pb , value_type ) ;
} else if ( ! strcmp ( name , " AspectRatioY " ) ) {
asf - > dar [ 0 ] . den = get_value ( s - > pb , value_type ) ;
} else
get_tag ( s , name , value_type , value_len ) ;
}
return 0 ;
}
static int asf_read_language_list ( AVFormatContext * s , int64_t size )
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:55 +02:00
ASFContext * asf = s - > priv_data ;
int j , ret ;
2011-02-21 17:43:01 +02:00
int stream_count = avio_rl16 ( pb ) ;
2011-02-09 22:55:55 +02:00
for ( j = 0 ; j < stream_count ; j + + ) {
char lang [ 6 ] ;
2011-02-21 17:43:01 +02:00
unsigned int lang_len = avio_r8 ( pb ) ;
2011-02-09 22:55:55 +02:00
if ( ( ret = avio_get_str16le ( pb , lang_len , lang , sizeof ( lang ) ) ) < lang_len )
2011-03-15 10:14:38 +02:00
avio_skip ( pb , lang_len - ret ) ;
2011-02-09 22:55:55 +02:00
if ( j < 128 )
av_strlcpy ( asf - > stream_languages [ j ] , lang , sizeof ( * asf - > stream_languages ) ) ;
}
return 0 ;
}
static int asf_read_metadata ( AVFormatContext * s , int64_t size )
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:55 +02:00
ASFContext * asf = s - > priv_data ;
2011-06-01 19:26:27 +03:00
int n , stream_num , name_len , value_len , value_num ;
2011-02-09 22:55:55 +02:00
int ret , i ;
2011-02-21 17:43:01 +02:00
n = avio_rl16 ( pb ) ;
2011-02-09 22:55:55 +02:00
for ( i = 0 ; i < n ; i + + ) {
char name [ 1024 ] ;
2011-02-21 17:43:01 +02:00
avio_rl16 ( pb ) ; //lang_list_index
stream_num = avio_rl16 ( pb ) ;
name_len = avio_rl16 ( pb ) ;
2011-06-01 19:26:27 +03:00
avio_skip ( pb , 2 ) ; /* value_type */
2011-02-21 17:43:01 +02:00
value_len = avio_rl32 ( pb ) ;
2011-02-09 22:55:55 +02:00
if ( ( ret = avio_get_str16le ( pb , name_len , name , sizeof ( name ) ) ) < name_len )
2011-03-15 10:14:38 +02:00
avio_skip ( pb , name_len - ret ) ;
2011-02-09 22:55:55 +02:00
//av_log(s, AV_LOG_ERROR, "%d %d %d %d %d <%s>\n", i, stream_num, name_len, value_type, value_len, name);
2011-02-21 17:43:01 +02:00
value_num = avio_rl16 ( pb ) ; //we should use get_value() here but it does not work 2 is le16 here but le32 elsewhere
2011-03-15 10:14:38 +02:00
avio_skip ( pb , value_len - 2 ) ;
2011-02-09 22:55:55 +02:00
if ( stream_num < 128 ) {
if ( ! strcmp ( name , " AspectRatioX " ) ) asf - > dar [ stream_num ] . num = value_num ;
else if ( ! strcmp ( name , " AspectRatioY " ) ) asf - > dar [ stream_num ] . den = value_num ;
}
}
return 0 ;
}
static int asf_read_marker ( AVFormatContext * s , int64_t size )
{
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:55 +02:00
int i , count , name_len , ret ;
char name [ 1024 ] ;
2011-02-21 17:43:01 +02:00
avio_rl64 ( pb ) ; // reserved 16 bytes
avio_rl64 ( pb ) ; // ...
count = avio_rl32 ( pb ) ; // markers count
avio_rl16 ( pb ) ; // reserved 2 bytes
name_len = avio_rl16 ( pb ) ; // name length
2011-02-09 22:55:55 +02:00
for ( i = 0 ; i < name_len ; i + + ) {
2011-02-21 17:43:01 +02:00
avio_r8 ( pb ) ; // skip the name
2011-02-09 22:55:55 +02:00
}
for ( i = 0 ; i < count ; i + + ) {
int64_t pres_time ;
int name_len ;
2011-02-21 17:43:01 +02:00
avio_rl64 ( pb ) ; // offset, 8 bytes
pres_time = avio_rl64 ( pb ) ; // presentation time
avio_rl16 ( pb ) ; // entry length
avio_rl32 ( pb ) ; // send time
avio_rl32 ( pb ) ; // flags
name_len = avio_rl32 ( pb ) ; // name length
2011-02-09 22:55:55 +02:00
if ( ( ret = avio_get_str16le ( pb , name_len * 2 , name , sizeof ( name ) ) ) < name_len )
2011-03-15 10:14:38 +02:00
avio_skip ( pb , name_len - ret ) ;
2011-10-17 09:58:50 +03:00
avpriv_new_chapter ( s , i , ( AVRational ) { 1 , 10000000 } , pres_time , AV_NOPTS_VALUE , name ) ;
2011-02-09 22:55:55 +02:00
}
return 0 ;
}
2012-01-12 15:20:36 +03:00
static int asf_read_header ( AVFormatContext * s )
2001-07-22 17:18:56 +03:00
{
2002-05-20 19:31:13 +03:00
ASFContext * asf = s - > priv_data ;
2009-03-18 16:03:40 +02:00
ff_asf_guid g ;
2011-02-20 12:04:12 +02:00
AVIOContext * pb = s - > pb ;
2011-02-09 22:55:56 +02:00
int i ;
2003-02-11 18:35:48 +02:00
int64_t gsize ;
2001-07-22 17:18:56 +03:00
2010-12-26 03:26:29 +02:00
ff_get_guid ( pb , & g ) ;
if ( ff_guidcmp ( & g , & ff_asf_header ) )
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2011-02-21 17:43:01 +02:00
avio_rl64 ( pb ) ;
avio_rl32 ( pb ) ;
avio_r8 ( pb ) ;
avio_r8 ( pb ) ;
2002-08-09 01:04:01 +03:00
memset ( & asf - > asfid2avid , - 1 , sizeof ( asf - > asfid2avid ) ) ;
2001-07-22 17:18:56 +03:00
for ( ; ; ) {
2011-03-03 21:11:45 +02:00
uint64_t gpos = avio_tell ( pb ) ;
2010-12-26 03:26:29 +02:00
ff_get_guid ( pb , & g ) ;
2011-02-21 17:43:01 +02:00
gsize = avio_rl64 ( pb ) ;
2011-01-29 18:46:18 +02:00
av_dlog ( s , " %08 " PRIx64 " : " , gpos ) ;
2001-07-22 17:18:56 +03:00
print_guid ( & g ) ;
2011-01-29 18:46:18 +02:00
av_dlog ( s , " size=0x% " PRIx64 " \n " , gsize ) ;
2010-12-26 03:26:29 +02:00
if ( ! ff_guidcmp ( & g , & ff_asf_data_header ) ) {
2011-03-03 21:11:45 +02:00
asf - > data_object_offset = avio_tell ( pb ) ;
2007-03-11 05:36:17 +02:00
// if not streaming, gsize is not unlimited (how?), and there is enough space in the file..
if ( ! ( asf - > hdr . flags & 0x01 ) & & gsize > = 100 ) {
asf - > data_object_size = gsize - 24 ;
} else {
asf - > data_object_size = ( uint64_t ) - 1 ;
}
break ;
}
2001-07-22 17:18:56 +03:00
if ( gsize < 24 )
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2010-12-26 03:26:29 +02:00
if ( ! ff_guidcmp ( & g , & ff_asf_file_header ) ) {
2012-02-17 23:21:22 +03:00
int ret = asf_read_file_properties ( s , gsize ) ;
if ( ret < 0 )
return ret ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_stream_header ) ) {
2011-02-09 22:55:57 +02:00
asf_read_stream_properties ( s , gsize ) ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_comment_header ) ) {
2011-02-09 22:55:55 +02:00
asf_read_content_desc ( s , gsize ) ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_language_guid ) ) {
2011-02-09 22:55:55 +02:00
asf_read_language_list ( s , gsize ) ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_extended_content_header ) ) {
2011-02-09 22:55:55 +02:00
asf_read_ext_content_desc ( s , gsize ) ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_metadata_header ) ) {
2011-02-09 22:55:55 +02:00
asf_read_metadata ( s , gsize ) ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_ext_stream_header ) ) {
2011-02-09 22:55:55 +02:00
asf_read_ext_stream_properties ( s , gsize ) ;
2006-01-21 01:48:16 +02:00
// there could be a optional stream properties object to follow
// if so the next iteration will pick it up
2010-06-23 05:04:55 +03:00
continue ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_head1_guid ) ) {
ff_get_guid ( pb , & g ) ;
2011-06-01 19:26:27 +03:00
avio_skip ( pb , 6 ) ;
2010-06-23 05:04:55 +03:00
continue ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_marker_header ) ) {
2011-02-09 22:55:55 +02:00
asf_read_marker ( s , gsize ) ;
2001-07-22 17:18:56 +03:00
} else if ( url_feof ( pb ) ) {
2012-06-14 03:30:55 +03:00
return AVERROR_EOF ;
2001-07-22 17:18:56 +03:00
} else {
2009-10-12 02:09:33 +03:00
if ( ! s - > keylen ) {
2010-12-26 03:26:29 +02:00
if ( ! ff_guidcmp ( & g , & ff_asf_content_encryption ) ) {
2011-10-16 06:04:48 +03:00
unsigned int len ;
AVPacket pkt ;
2009-10-12 02:09:33 +03:00
av_log ( s , AV_LOG_WARNING , " DRM protected stream detected, decoding will likely fail! \n " ) ;
2011-10-16 06:04:48 +03:00
len = avio_rl32 ( pb ) ;
av_log ( s , AV_LOG_DEBUG , " Secret data: \n " ) ;
av_get_packet ( pb , & pkt , len ) ; av_hex_dump_log ( s , AV_LOG_DEBUG , pkt . data , pkt . size ) ; av_free_packet ( & pkt ) ;
len = avio_rl32 ( pb ) ;
get_tag ( s , " ASF_Protection_Type " , - 1 , len ) ;
len = avio_rl32 ( pb ) ;
get_tag ( s , " ASF_Key_ID " , - 1 , len ) ;
len = avio_rl32 ( pb ) ;
get_tag ( s , " ASF_License_URL " , - 1 , len ) ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_ext_content_encryption ) ) {
2009-10-12 02:09:33 +03:00
av_log ( s , AV_LOG_WARNING , " Ext DRM protected stream detected, decoding will likely fail! \n " ) ;
2011-10-16 05:41:11 +03:00
av_dict_set ( & s - > metadata , " encryption " , " ASF Extended Content Encryption " , 0 ) ;
2010-12-26 03:26:29 +02:00
} else if ( ! ff_guidcmp ( & g , & ff_asf_digital_signature ) ) {
2011-10-16 05:44:42 +03:00
av_log ( s , AV_LOG_INFO , " Digital signature detected! \n " ) ;
2009-10-12 02:09:33 +03:00
}
}
2001-07-22 17:18:56 +03:00
}
2011-03-03 21:11:45 +02:00
if ( avio_tell ( pb ) ! = gpos + gsize )
av_log ( s , AV_LOG_DEBUG , " gpos mismatch our pos=% " PRIu64 " , end=% " PRIu64 " \n " , avio_tell ( pb ) - gpos , gsize ) ;
2011-02-28 15:57:54 +02:00
avio_seek ( pb , gpos + gsize , SEEK_SET ) ;
2001-07-22 17:18:56 +03:00
}
2010-12-26 03:26:29 +02:00
ff_get_guid ( pb , & g ) ;
2011-02-21 17:43:01 +02:00
avio_rl64 ( pb ) ;
avio_r8 ( pb ) ;
avio_r8 ( pb ) ;
2002-08-09 01:04:01 +03:00
if ( url_feof ( pb ) )
2012-06-14 03:30:55 +03:00
return AVERROR_EOF ;
2011-03-03 21:11:45 +02:00
asf - > data_offset = avio_tell ( pb ) ;
2001-07-22 17:18:56 +03:00
asf - > packet_size_left = 0 ;
2007-02-01 01:32:01 +02:00
for ( i = 0 ; i < 128 ; i + + ) {
int stream_num = asf - > asfid2avid [ i ] ;
2007-04-30 18:56:11 +03:00
if ( stream_num > = 0 ) {
2008-08-24 02:43:20 +03:00
AVStream * st = s - > streams [ stream_num ] ;
if ( ! st - > codec - > bit_rate )
2011-02-09 22:55:54 +02:00
st - > codec - > bit_rate = asf - > stream_bitrates [ i ] ;
2011-02-09 22:55:53 +02:00
if ( asf - > dar [ i ] . num > 0 & & asf - > dar [ i ] . den > 0 ) {
2008-08-24 02:43:20 +03:00
av_reduce ( & st - > sample_aspect_ratio . num ,
& st - > sample_aspect_ratio . den ,
2011-02-09 22:55:53 +02:00
asf - > dar [ i ] . num , asf - > dar [ i ] . den , INT_MAX ) ;
} else if ( ( asf - > dar [ 0 ] . num > 0 ) & & ( asf - > dar [ 0 ] . den > 0 ) & & ( st - > codec - > codec_type = = AVMEDIA_TYPE_VIDEO ) ) // Use ASF container value if the stream doesn't AR set.
2010-09-23 06:40:06 +03:00
av_reduce ( & st - > sample_aspect_ratio . num ,
& st - > sample_aspect_ratio . den ,
2011-02-09 22:55:53 +02:00
asf - > dar [ 0 ] . num , asf - > dar [ 0 ] . den , INT_MAX ) ;
2010-09-23 06:40:06 +03:00
//av_log(s, AV_LOG_INFO, "i=%d, st->codec->codec_type:%d, dar %d:%d sar=%d:%d\n", i, st->codec->codec_type, dar[i].num, dar[i].den, st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
2009-05-12 15:35:46 +03:00
// copy and convert language codes to the frontend
if ( asf - > streams [ i ] . stream_language_index < 128 ) {
const char * rfc1766 = asf - > stream_languages [ asf - > streams [ i ] . stream_language_index ] ;
if ( rfc1766 & & strlen ( rfc1766 ) > 1 ) {
const char primary_tag [ 3 ] = { rfc1766 [ 0 ] , rfc1766 [ 1 ] , ' \0 ' } ; // ignore country code if any
const char * iso6392 = av_convert_lang_to ( primary_tag , AV_LANG_ISO639_2_BIBL ) ;
if ( iso6392 )
2011-05-22 13:46:29 +03:00
av_dict_set ( & st - > metadata , " language " , iso6392 , 0 ) ;
2009-05-12 15:35:46 +03:00
}
}
2007-02-01 01:32:01 +02:00
}
}
2010-10-16 16:20:41 +03:00
ff_metadata_conv ( & s - > metadata , NULL , ff_asf_metadata_conv ) ;
2010-10-15 22:04:25 +03:00
2001-07-22 17:18:56 +03:00
return 0 ;
}
2002-08-08 19:43:47 +03:00
# define DO_2BITS(bits, var, defval) \
switch ( bits & 3 ) \
{ \
2011-02-21 17:43:01 +02:00
case 3 : var = avio_rl32 ( pb ) ; rsize + = 4 ; break ; \
case 2 : var = avio_rl16 ( pb ) ; rsize + = 2 ; break ; \
case 1 : var = avio_r8 ( pb ) ; rsize + + ; break ; \
2002-08-08 19:43:47 +03:00
default : var = defval ; break ; \
}
2009-06-09 23:58:32 +03:00
/**
* Load a single ASF packet into the demuxer .
* @ param s demux context
* @ param pb context to read data from
2010-03-30 18:50:57 +03:00
* @ return 0 on success , < 0 on error
2009-06-09 23:58:32 +03:00
*/
2011-02-20 12:04:12 +02:00
static int ff_asf_get_packet ( AVFormatContext * s , AVIOContext * pb )
2001-07-22 17:18:56 +03:00
{
ASFContext * asf = s - > priv_data ;
2002-08-08 19:43:47 +03:00
uint32_t packet_length , padsize ;
2007-03-30 19:20:40 +03:00
int rsize = 8 ;
2007-01-23 23:25:06 +02:00
int c , d , e , off ;
2009-07-03 14:18:07 +03:00
// if we do not know packet size, allow skipping up to 32 kB
off = 32768 ;
2012-04-06 16:54:23 +03:00
if ( asf - > no_resync_search )
off = 3 ;
else if ( s - > packet_size > 0 )
2011-03-03 21:11:45 +02:00
off = ( avio_tell ( pb ) - s - > data_offset ) % s - > packet_size + 3 ;
2007-01-23 23:25:06 +02:00
c = d = e = - 1 ;
while ( off - - > 0 ) {
c = d ; d = e ;
2011-02-21 17:43:01 +02:00
e = avio_r8 ( pb ) ;
2007-01-23 23:25:06 +02:00
if ( c = = 0x82 & & ! d & & ! e )
break ;
}
2005-12-17 20:14:38 +02:00
2002-08-09 16:06:27 +03:00
if ( c ! = 0x82 ) {
2009-07-26 22:09:35 +03:00
/**
* This code allows handling of - EAGAIN at packet boundaries ( i . e .
* if the packet sync code above triggers - EAGAIN ) . This does not
* imply complete - EAGAIN handling support at random positions in
* the stream .
*/
2011-03-14 21:38:55 +02:00
if ( pb - > error = = AVERROR ( EAGAIN ) )
2009-07-26 22:09:35 +03:00
return AVERROR ( EAGAIN ) ;
2002-11-05 12:14:48 +02:00
if ( ! url_feof ( pb ) )
2011-03-03 21:11:45 +02:00
av_log ( s , AV_LOG_ERROR , " ff asf bad header %x at:% " PRId64 " \n " , c , avio_tell ( pb ) ) ;
2002-08-08 19:43:47 +03:00
}
2007-03-30 19:20:40 +03:00
if ( ( c & 0x8f ) = = 0x82 ) {
2007-01-23 23:25:06 +02:00
if ( d | | e ) {
2002-11-05 12:14:48 +02:00
if ( ! url_feof ( pb ) )
2005-12-22 03:10:11 +02:00
av_log ( s , AV_LOG_ERROR , " ff asf bad non zero \n " ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2005-12-22 03:10:11 +02:00
}
2011-02-21 17:43:01 +02:00
c = avio_r8 ( pb ) ;
d = avio_r8 ( pb ) ;
2007-03-30 19:20:40 +03:00
rsize + = 3 ;
2011-12-25 01:21:40 +03:00
} else if ( ! url_feof ( pb ) ) {
2011-02-28 15:57:54 +02:00
avio_seek ( pb , - 1 , SEEK_CUR ) ; //FIXME
2001-07-22 17:18:56 +03:00
}
2002-08-08 19:43:47 +03:00
2007-03-30 19:20:40 +03:00
asf - > packet_flags = c ;
asf - > packet_property = d ;
2002-08-08 19:43:47 +03:00
2009-06-25 02:04:05 +03:00
DO_2BITS ( asf - > packet_flags > > 5 , packet_length , s - > packet_size ) ;
2002-08-08 19:43:47 +03:00
DO_2BITS ( asf - > packet_flags > > 1 , padsize , 0 ) ; // sequence ignored
DO_2BITS ( asf - > packet_flags > > 3 , padsize , 0 ) ; // padding length
2006-09-28 00:19:47 +03:00
//the following checks prevent overflows and infinite loops
2009-07-06 20:08:32 +03:00
if ( ! packet_length | | packet_length > = ( 1U < < 29 ) ) {
2011-03-03 21:11:45 +02:00
av_log ( s , AV_LOG_ERROR , " invalid packet_length %d at:% " PRId64 " \n " , packet_length , avio_tell ( pb ) ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2006-09-28 00:19:47 +03:00
}
2007-01-22 23:33:26 +02:00
if ( padsize > = packet_length ) {
2011-03-03 21:11:45 +02:00
av_log ( s , AV_LOG_ERROR , " invalid padsize %d at:% " PRId64 " \n " , padsize , avio_tell ( pb ) ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2006-09-28 00:19:47 +03:00
}
2011-02-21 17:43:01 +02:00
asf - > packet_timestamp = avio_rl32 ( pb ) ;
avio_rl16 ( pb ) ; /* duration */
2002-08-09 01:04:01 +03:00
// rsize has at least 11 bytes which have to be present
2002-08-08 19:43:47 +03:00
if ( asf - > packet_flags & 0x01 ) {
2011-02-21 17:43:01 +02:00
asf - > packet_segsizetype = avio_r8 ( pb ) ; rsize + + ;
2002-08-08 19:43:47 +03:00
asf - > packet_segments = asf - > packet_segsizetype & 0x3f ;
} else {
2005-12-22 03:10:11 +02:00
asf - > packet_segments = 1 ;
2002-08-08 19:43:47 +03:00
asf - > packet_segsizetype = 0x80 ;
}
2012-02-17 23:21:18 +03:00
if ( rsize > packet_length - padsize ) {
asf - > packet_size_left = 0 ;
av_log ( s , AV_LOG_ERROR ,
" invalid packet header length %d for pktlen %d-%d at % " PRId64 " \n " ,
rsize , packet_length , padsize , avio_tell ( pb ) ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2012-02-17 23:21:18 +03:00
}
2002-08-08 19:43:47 +03:00
asf - > packet_size_left = packet_length - padsize - rsize ;
2002-11-05 19:16:41 +02:00
if ( packet_length < asf - > hdr . min_pktsize )
padsize + = asf - > hdr . min_pktsize - packet_length ;
2002-08-08 19:43:47 +03:00
asf - > packet_padsize = padsize ;
2011-01-29 18:46:18 +02:00
av_dlog ( s , " packet: size=%d padsize=%d left=%d \n " , s - > packet_size , asf - > packet_padsize , asf - > packet_size_left ) ;
2001-07-22 17:18:56 +03:00
return 0 ;
}
2007-01-22 14:55:23 +02:00
/**
*
* @ return < 0 if error
*/
2011-02-20 12:04:12 +02:00
static int asf_read_frame_header ( AVFormatContext * s , AVIOContext * pb ) {
2007-01-22 14:55:23 +02:00
ASFContext * asf = s - > priv_data ;
int rsize = 1 ;
2011-02-21 17:43:01 +02:00
int num = avio_r8 ( pb ) ;
2011-11-15 15:06:36 +03:00
int64_t ts0 , ts1 av_unused ;
2007-01-22 14:55:23 +02:00
asf - > packet_segments - - ;
asf - > packet_key_frame = num > > 7 ;
asf - > stream_index = asf - > asfid2avid [ num & 0x7f ] ;
// sequence should be ignored!
DO_2BITS ( asf - > packet_property > > 4 , asf - > packet_seq , 0 ) ;
DO_2BITS ( asf - > packet_property > > 2 , asf - > packet_frag_offset , 0 ) ;
DO_2BITS ( asf - > packet_property , asf - > packet_replic_size , 0 ) ;
//printf("key:%d stream:%d seq:%d offset:%d replic_size:%d\n", asf->packet_key_frame, asf->stream_index, asf->packet_seq, //asf->packet_frag_offset, asf->packet_replic_size);
2011-11-01 00:42:45 +03:00
if ( rsize + asf - > packet_replic_size > asf - > packet_size_left ) {
av_log ( s , AV_LOG_ERROR , " packet_replic_size %d is invalid \n " , asf - > packet_replic_size ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2011-11-01 00:42:45 +03:00
}
2007-01-22 14:55:23 +02:00
if ( asf - > packet_replic_size > = 8 ) {
2011-02-21 17:43:01 +02:00
asf - > packet_obj_size = avio_rl32 ( pb ) ;
2007-01-22 14:55:23 +02:00
if ( asf - > packet_obj_size > = ( 1 < < 24 ) | | asf - > packet_obj_size < = 0 ) {
av_log ( s , AV_LOG_ERROR , " packet_obj_size invalid \n " ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2007-01-22 14:55:23 +02:00
}
2011-02-21 17:43:01 +02:00
asf - > packet_frag_timestamp = avio_rl32 ( pb ) ; // timestamp
2007-02-10 05:36:12 +02:00
if ( asf - > packet_replic_size > = 8 + 38 + 4 ) {
// for(i=0; i<asf->packet_replic_size-8; i++)
2011-02-21 17:43:01 +02:00
// av_log(s, AV_LOG_DEBUG, "%02X ",avio_r8(pb));
2007-02-10 05:36:12 +02:00
// av_log(s, AV_LOG_DEBUG, "\n");
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 10 ) ;
2011-02-21 17:43:01 +02:00
ts0 = avio_rl64 ( pb ) ;
2011-11-15 02:57:08 +03:00
ts1 = avio_rl64 ( pb ) ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , 12 ) ;
2011-02-21 17:43:01 +02:00
avio_rl32 ( pb ) ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , asf - > packet_replic_size - 8 - 38 - 4 ) ;
2007-02-10 05:36:12 +02:00
if ( ts0 ! = - 1 ) asf - > packet_frag_timestamp = ts0 / 10000 ;
else asf - > packet_frag_timestamp = AV_NOPTS_VALUE ;
} else
2011-03-15 10:14:38 +02:00
avio_skip ( pb , asf - > packet_replic_size - 8 ) ;
2007-01-22 14:55:23 +02:00
rsize + = asf - > packet_replic_size ; // FIXME - check validity
} else if ( asf - > packet_replic_size = = 1 ) {
2007-12-23 20:08:00 +02:00
// multipacket - frag_offset is beginning timestamp
2007-01-22 14:55:23 +02:00
asf - > packet_time_start = asf - > packet_frag_offset ;
asf - > packet_frag_offset = 0 ;
asf - > packet_frag_timestamp = asf - > packet_timestamp ;
2011-02-21 17:43:01 +02:00
asf - > packet_time_delta = avio_r8 ( pb ) ;
2007-01-22 14:55:23 +02:00
rsize + + ;
} else if ( asf - > packet_replic_size ! = 0 ) {
av_log ( s , AV_LOG_ERROR , " unexpected packet_replic_size of %d \n " , asf - > packet_replic_size ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2007-01-22 14:55:23 +02:00
}
if ( asf - > packet_flags & 0x01 ) {
DO_2BITS ( asf - > packet_segsizetype > > 6 , asf - > packet_frag_size , 0 ) ; // 0 is illegal
2011-05-12 17:20:27 +03:00
if ( rsize > asf - > packet_size_left ) {
av_log ( s , AV_LOG_ERROR , " packet_replic_size is invalid \n " ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2011-05-12 17:20:27 +03:00
} else if ( asf - > packet_frag_size > asf - > packet_size_left - rsize ) {
2011-04-28 01:42:16 +03:00
if ( asf - > packet_frag_size > asf - > packet_size_left - rsize + asf - > packet_padsize ) {
av_log ( s , AV_LOG_ERROR , " packet_frag_size is invalid (%d-%d) \n " , asf - > packet_size_left , rsize ) ;
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2011-04-28 01:42:16 +03:00
} else {
int diff = asf - > packet_frag_size - ( asf - > packet_size_left - rsize ) ;
asf - > packet_size_left + = diff ;
asf - > packet_padsize - = diff ;
}
2007-01-22 23:17:54 +02:00
}
2007-01-22 14:55:23 +02:00
//printf("Fragsize %d\n", asf->packet_frag_size);
} else {
asf - > packet_frag_size = asf - > packet_size_left - rsize ;
//printf("Using rest %d %d %d\n", asf->packet_frag_size, asf->packet_size_left, rsize);
}
if ( asf - > packet_replic_size = = 1 ) {
asf - > packet_multi_size = asf - > packet_frag_size ;
if ( asf - > packet_multi_size > asf - > packet_size_left )
2012-06-14 03:30:55 +03:00
return AVERROR_INVALIDDATA ;
2007-01-22 14:55:23 +02:00
}
asf - > packet_size_left - = rsize ;
//printf("___objsize____ %d %d rs:%d\n", asf->packet_obj_size, asf->packet_frag_offset, rsize);
return 0 ;
}
2009-06-09 23:58:32 +03:00
/**
* Parse data from individual ASF packets ( which were previously loaded
* with asf_get_packet ( ) ) .
* @ param s demux context
* @ param pb context to read data from
* @ param pkt pointer to store packet data into
2010-03-30 18:50:57 +03:00
* @ return 0 if data was stored in pkt , < 0 on error or 1 if more ASF
2009-06-09 23:58:32 +03:00
* packets need to be loaded ( through asf_get_packet ( ) )
*/
2011-02-20 12:04:12 +02:00
static int ff_asf_parse_packet ( AVFormatContext * s , AVIOContext * pb , AVPacket * pkt )
2001-07-22 17:18:56 +03:00
{
ASFContext * asf = s - > priv_data ;
2002-08-08 19:43:47 +03:00
ASFStream * asf_st = 0 ;
for ( ; ; ) {
2010-12-11 23:41:47 +02:00
int ret ;
2007-01-22 23:28:56 +02:00
if ( url_feof ( pb ) )
2009-04-16 03:41:31 +03:00
return AVERROR_EOF ;
2005-12-22 03:10:11 +02:00
if ( asf - > packet_size_left < FRAME_HEADER_SIZE
| | asf - > packet_segments < 1 ) {
//asf->packet_size_left <= asf->packet_padsize) {
int ret = asf - > packet_size_left + asf - > packet_padsize ;
2011-03-03 21:11:45 +02:00
//printf("PacketLeftSize:%d Pad:%d Pos:%"PRId64"\n", asf->packet_size_left, asf->packet_padsize, avio_tell(pb));
2006-09-28 00:19:47 +03:00
assert ( ret > = 0 ) ;
2005-12-22 03:10:11 +02:00
/* fail safe */
2011-03-15 10:14:38 +02:00
avio_skip ( pb , ret ) ;
2007-01-22 14:52:49 +02:00
2011-03-03 21:11:45 +02:00
asf - > packet_pos = avio_tell ( pb ) ;
2006-07-29 19:07:19 +03:00
if ( asf - > data_object_size ! = ( uint64_t ) - 1 & &
( asf - > packet_pos - asf - > data_object_offset > = asf - > data_object_size ) )
2009-04-17 17:05:57 +03:00
return AVERROR_EOF ; /* Do not exceed the size of the data object */
2008-12-13 19:18:11 +02:00
return 1 ;
2005-12-22 03:10:11 +02:00
}
if ( asf - > packet_time_start = = 0 ) {
2009-01-07 16:50:19 +02:00
if ( asf_read_frame_header ( s , pb ) < 0 ) {
2007-01-22 14:55:23 +02:00
asf - > packet_segments = 0 ;
2007-01-22 01:03:09 +02:00
continue ;
2004-01-14 23:27:59 +02:00
}
2005-12-22 03:10:11 +02:00
if ( asf - > stream_index < 0
2005-03-17 03:25:01 +02:00
| | s - > streams [ asf - > stream_index ] - > discard > = AVDISCARD_ALL
| | ( ! asf - > packet_key_frame & & s - > streams [ asf - > stream_index ] - > discard > = AVDISCARD_NONKEY )
) {
2002-08-09 16:06:27 +03:00
asf - > packet_time_start = 0 ;
2005-12-22 03:10:11 +02:00
/* unhandled packet (should not happen) */
2011-03-15 10:14:38 +02:00
avio_skip ( pb , asf - > packet_frag_size ) ;
2005-12-22 03:10:11 +02:00
asf - > packet_size_left - = asf - > packet_frag_size ;
2005-01-22 15:36:02 +02:00
if ( asf - > stream_index < 0 )
2007-01-22 14:55:23 +02:00
av_log ( s , AV_LOG_ERROR , " ff asf skip %d (unknown stream) \n " , asf - > packet_frag_size ) ;
2002-08-09 16:06:27 +03:00
continue ;
2005-12-22 03:10:11 +02:00
}
asf - > asf_st = s - > streams [ asf - > stream_index ] - > priv_data ;
}
asf_st = asf - > asf_st ;
if ( asf - > packet_replic_size = = 1 ) {
2007-12-23 20:08:00 +02:00
// frag_offset is here used as the beginning timestamp
2005-12-22 03:10:11 +02:00
asf - > packet_frag_timestamp = asf - > packet_time_start ;
asf - > packet_time_start + = asf - > packet_time_delta ;
2011-02-21 17:43:01 +02:00
asf - > packet_obj_size = asf - > packet_frag_size = avio_r8 ( pb ) ;
2005-12-22 03:10:11 +02:00
asf - > packet_size_left - - ;
2002-08-09 01:04:01 +03:00
asf - > packet_multi_size - - ;
2005-12-22 03:10:11 +02:00
if ( asf - > packet_multi_size < asf - > packet_obj_size )
{
asf - > packet_time_start = 0 ;
2011-03-15 10:14:38 +02:00
avio_skip ( pb , asf - > packet_multi_size ) ;
2005-12-22 03:10:11 +02:00
asf - > packet_size_left - = asf - > packet_multi_size ;
2002-08-09 01:04:01 +03:00
continue ;
2005-12-22 03:10:11 +02:00
}
asf - > packet_multi_size - = asf - > packet_obj_size ;
//printf("COMPRESS size %d %d %d ms:%d\n", asf->packet_obj_size, asf->packet_frag_timestamp, asf->packet_size_left, asf->packet_multi_size);
}
2007-07-27 03:29:33 +03:00
if ( /*asf->packet_frag_size == asf->packet_obj_size*/
asf_st - > frag_offset + asf - > packet_frag_size < = asf_st - > pkt . size
& & asf_st - > frag_offset + asf - > packet_frag_size > asf - > packet_obj_size ) {
av_log ( s , AV_LOG_INFO , " ignoring invalid packet_obj_size (%d %d %d %d) \n " ,
asf_st - > frag_offset , asf - > packet_frag_size ,
asf - > packet_obj_size , asf_st - > pkt . size ) ;
asf - > packet_obj_size = asf_st - > pkt . size ;
}
2007-01-29 16:54:55 +02:00
if ( asf_st - > pkt . size ! = asf - > packet_obj_size
| | asf_st - > frag_offset + asf - > packet_frag_size > asf_st - > pkt . size ) { //FIXME is this condition sufficient?
2007-01-22 19:01:01 +02:00
if ( asf_st - > pkt . data ) {
av_log ( s , AV_LOG_INFO , " freeing incomplete packet size %d, new %d \n " , asf_st - > pkt . size , asf - > packet_obj_size ) ;
asf_st - > frag_offset = 0 ;
av_free_packet ( & asf_st - > pkt ) ;
}
2005-12-22 03:10:11 +02:00
/* new packet */
av_new_packet ( & asf_st - > pkt , asf - > packet_obj_size ) ;
asf_st - > seq = asf - > packet_seq ;
2011-03-17 15:56:14 +02:00
asf_st - > pkt . dts = asf - > packet_frag_timestamp - asf - > hdr . preroll ;
2005-12-22 03:10:11 +02:00
asf_st - > pkt . stream_index = asf - > stream_index ;
2005-12-17 20:14:38 +02:00
asf_st - > pkt . pos =
asf_st - > packet_pos = asf - > packet_pos ;
2011-04-09 16:49:51 +03:00
if ( asf_st - > pkt . data & & asf_st - > palette_changed ) {
uint8_t * pal ;
2011-12-20 07:16:51 +03:00
pal = av_packet_new_side_data ( & asf_st - > pkt , AV_PKT_DATA_PALETTE ,
2011-04-09 16:49:51 +03:00
AVPALETTE_SIZE ) ;
if ( ! pal ) {
av_log ( s , AV_LOG_ERROR , " Cannot append palette to packet \n " ) ;
} else {
memcpy ( pal , asf_st - > palette , AVPALETTE_SIZE ) ;
asf_st - > palette_changed = 0 ;
}
}
2005-12-17 20:14:38 +02:00
//printf("new packet: stream:%d key:%d packet_key:%d audio:%d size:%d\n",
2010-03-31 15:29:58 +03:00
//asf->stream_index, asf->packet_key_frame, asf_st->pkt.flags & AV_PKT_FLAG_KEY,
2010-03-31 02:30:55 +03:00
//s->streams[asf->stream_index]->codec->codec_type == AVMEDIA_TYPE_AUDIO, asf->packet_obj_size);
if ( s - > streams [ asf - > stream_index ] - > codec - > codec_type = = AVMEDIA_TYPE_AUDIO )
2005-12-22 03:10:11 +02:00
asf - > packet_key_frame = 1 ;
if ( asf - > packet_key_frame )
2010-03-31 15:29:58 +03:00
asf_st - > pkt . flags | = AV_PKT_FLAG_KEY ;
2005-12-22 03:10:11 +02:00
}
/* read data */
//printf("READ PACKET s:%d os:%d o:%d,%d l:%d DATA:%p\n",
2009-06-25 02:04:05 +03:00
// s->packet_size, asf_st->pkt.size, asf->packet_frag_offset,
2005-12-22 03:10:11 +02:00
// asf_st->frag_offset, asf->packet_frag_size, asf_st->pkt.data);
asf - > packet_size_left - = asf - > packet_frag_size ;
if ( asf - > packet_size_left < 0 )
2002-08-09 01:04:01 +03:00
continue ;
2007-01-22 18:37:45 +02:00
if ( asf - > packet_frag_offset > = asf_st - > pkt . size
| | asf - > packet_frag_size > asf_st - > pkt . size - asf - > packet_frag_offset ) {
av_log ( s , AV_LOG_ERROR , " packet fragment position invalid %u,%u not in %u \n " ,
asf - > packet_frag_offset , asf - > packet_frag_size , asf_st - > pkt . size ) ;
continue ;
}
2011-02-21 17:43:01 +02:00
ret = avio_read ( pb , asf_st - > pkt . data + asf - > packet_frag_offset ,
2010-12-11 23:41:47 +02:00
asf - > packet_frag_size ) ;
2010-12-18 15:18:52 +02:00
if ( ret ! = asf - > packet_frag_size ) {
if ( ret < 0 | | asf - > packet_frag_offset + ret = = 0 )
return ret < 0 ? ret : AVERROR_EOF ;
if ( asf_st - > ds_span > 1 ) {
// scrambling, we can either drop it completely or fill the remainder
// TODO: should we fill the whole packet instead of just the current
// fragment?
memset ( asf_st - > pkt . data + asf - > packet_frag_offset + ret , 0 ,
asf - > packet_frag_size - ret ) ;
ret = asf - > packet_frag_size ;
} else
// no scrambling, so we can return partial packets
av_shrink_packet ( & asf_st - > pkt , asf - > packet_frag_offset + ret ) ;
}
2007-10-20 17:25:02 +03:00
if ( s - > key & & s - > keylen = = 20 )
ff_asfcrypt_dec ( s - > key , asf_st - > pkt . data + asf - > packet_frag_offset ,
2010-12-18 15:18:52 +02:00
ret ) ;
asf_st - > frag_offset + = ret ;
2005-12-22 03:10:11 +02:00
/* test if whole packet is read */
if ( asf_st - > frag_offset = = asf_st - > pkt . size ) {
2007-09-02 18:58:43 +03:00
//workaround for macroshit radio DVR-MS files
2012-08-05 12:11:04 +03:00
if ( s - > streams [ asf - > stream_index ] - > codec - > codec_id = = AV_CODEC_ID_MPEG2VIDEO
2007-09-02 18:58:43 +03:00
& & asf_st - > pkt . size > 100 ) {
int i ;
for ( i = 0 ; i < asf_st - > pkt . size & & ! asf_st - > pkt . data [ i ] ; i + + ) ;
if ( i = = asf_st - > pkt . size ) {
av_log ( s , AV_LOG_DEBUG , " discarding ms fart \n " ) ;
asf_st - > frag_offset = 0 ;
av_free_packet ( & asf_st - > pkt ) ;
continue ;
}
}
2005-12-22 03:10:11 +02:00
/* return packet */
if ( asf_st - > ds_span > 1 ) {
2007-01-22 05:19:00 +02:00
if ( asf_st - > pkt . size ! = asf_st - > ds_packet_size * asf_st - > ds_span ) {
2007-08-06 23:37:45 +03:00
av_log ( s , AV_LOG_ERROR , " pkt.size != ds_packet_size * ds_span (%d %d %d) \n " , asf_st - > pkt . size , asf_st - > ds_packet_size , asf_st - > ds_span ) ;
2007-01-22 05:19:00 +02:00
} else {
2005-12-22 03:10:11 +02:00
/* packet descrambling */
2010-12-11 23:39:08 +02:00
uint8_t * newdata = av_malloc ( asf_st - > pkt . size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2005-12-22 03:10:11 +02:00
if ( newdata ) {
int offset = 0 ;
2010-12-11 23:39:08 +02:00
memset ( newdata + asf_st - > pkt . size , 0 , FF_INPUT_BUFFER_PADDING_SIZE ) ;
2005-12-22 03:10:11 +02:00
while ( offset < asf_st - > pkt . size ) {
int off = offset / asf_st - > ds_chunk_size ;
int row = off / asf_st - > ds_span ;
int col = off % asf_st - > ds_span ;
int idx = row + col * asf_st - > ds_packet_size / asf_st - > ds_chunk_size ;
//printf("off:%d row:%d col:%d idx:%d\n", off, row, col, idx);
2007-01-22 05:19:00 +02:00
assert ( offset + asf_st - > ds_chunk_size < = asf_st - > pkt . size ) ;
assert ( idx + 1 < = asf_st - > pkt . size / asf_st - > ds_chunk_size ) ;
2005-12-22 03:10:11 +02:00
memcpy ( newdata + offset ,
asf_st - > pkt . data + idx * asf_st - > ds_chunk_size ,
asf_st - > ds_chunk_size ) ;
offset + = asf_st - > ds_chunk_size ;
}
av_free ( asf_st - > pkt . data ) ;
asf_st - > pkt . data = newdata ;
}
2007-01-22 05:19:00 +02:00
}
2005-12-22 03:10:11 +02:00
}
asf_st - > frag_offset = 0 ;
2007-01-22 03:21:16 +02:00
* pkt = asf_st - > pkt ;
2005-12-22 03:10:11 +02:00
//printf("packet %d %d\n", asf_st->pkt.size, asf->packet_frag_size);
asf_st - > pkt . size = 0 ;
asf_st - > pkt . data = 0 ;
2012-03-22 02:10:37 +03:00
asf_st - > pkt . side_data_elems = 0 ;
asf_st - > pkt . side_data = NULL ;
2005-12-22 03:10:11 +02:00
break ; // packet completed
}
2001-07-22 17:18:56 +03:00
}
return 0 ;
}
2008-12-13 19:18:11 +02:00
static int asf_read_packet ( AVFormatContext * s , AVPacket * pkt )
{
ASFContext * asf = s - > priv_data ;
for ( ; ; ) {
int ret ;
/* parse cached packets, if any */
2008-12-18 03:28:29 +02:00
if ( ( ret = ff_asf_parse_packet ( s , s - > pb , pkt ) ) < = 0 )
2008-12-13 19:18:11 +02:00
return ret ;
2008-12-18 03:28:29 +02:00
if ( ( ret = ff_asf_get_packet ( s , s - > pb ) ) < 0 )
2008-12-13 19:18:11 +02:00
assert ( asf - > packet_size_left < FRAME_HEADER_SIZE | | asf - > packet_segments < 1 ) ;
asf - > packet_time_start = 0 ;
}
}
2004-01-14 15:32:49 +02:00
// Added to support seeking after packets have been read
// If information is not reset, read_packet fails due to
// leftover information from previous reads
static void asf_reset_header ( AVFormatContext * s )
{
ASFContext * asf = s - > priv_data ;
2004-01-14 20:18:47 +02:00
ASFStream * asf_st ;
int i ;
2004-01-14 15:32:49 +02:00
asf - > packet_size_left = 0 ;
asf - > packet_segments = 0 ;
asf - > packet_flags = 0 ;
asf - > packet_property = 0 ;
asf - > packet_timestamp = 0 ;
asf - > packet_segsizetype = 0 ;
asf - > packet_segments = 0 ;
asf - > packet_seq = 0 ;
asf - > packet_replic_size = 0 ;
asf - > packet_key_frame = 0 ;
asf - > packet_padsize = 0 ;
asf - > packet_frag_offset = 0 ;
asf - > packet_frag_size = 0 ;
asf - > packet_frag_timestamp = 0 ;
asf - > packet_multi_size = 0 ;
asf - > packet_obj_size = 0 ;
asf - > packet_time_delta = 0 ;
asf - > packet_time_start = 0 ;
2005-12-17 20:14:38 +02:00
2004-01-14 20:18:47 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
asf_st = s - > streams [ i ] - > priv_data ;
av_free_packet ( & asf_st - > pkt ) ;
asf_st - > frag_offset = 0 ;
asf_st - > seq = 0 ;
}
asf - > asf_st = NULL ;
2004-01-14 15:32:49 +02:00
}
2007-10-14 20:44:38 +03:00
static int asf_read_close ( AVFormatContext * s )
{
asf_reset_header ( s ) ;
2011-04-17 20:48:27 +03:00
2007-10-14 20:44:38 +03:00
return 0 ;
}
2004-04-12 19:50:03 +03:00
static int64_t asf_read_pts ( AVFormatContext * s , int stream_index , int64_t * ppos , int64_t pos_limit )
2004-01-14 15:32:49 +02:00
{
AVPacket pkt1 , * pkt = & pkt1 ;
2004-01-14 20:18:47 +02:00
ASFStream * asf_st ;
2004-01-14 16:45:53 +02:00
int64_t pts ;
2004-01-14 20:18:47 +02:00
int64_t pos = * ppos ;
2004-01-17 20:06:52 +02:00
int i ;
2010-06-24 18:10:06 +03:00
int64_t start_pos [ ASF_MAX_STREAMS ] ;
2005-12-17 20:14:38 +02:00
2004-01-17 20:06:52 +02:00
for ( i = 0 ; i < s - > nb_streams ; i + + ) {
start_pos [ i ] = pos ;
}
2005-12-17 20:14:38 +02:00
2009-07-03 14:18:07 +03:00
if ( s - > packet_size > 0 )
2009-07-03 14:18:56 +03:00
pos = ( pos + s - > packet_size - 1 - s - > data_offset ) / s - > packet_size * s - > packet_size + s - > data_offset ;
2004-04-12 19:50:03 +03:00
* ppos = pos ;
2011-09-12 05:06:55 +03:00
if ( avio_seek ( s - > pb , pos , SEEK_SET ) < 0 )
return AV_NOPTS_VALUE ;
2005-12-17 20:14:38 +02:00
2004-01-14 20:18:47 +02:00
//printf("asf_read_pts\n");
asf_reset_header ( s ) ;
2004-01-17 20:06:52 +02:00
for ( ; ; ) {
2004-01-14 20:18:47 +02:00
if ( av_read_frame ( s , pkt ) < 0 ) {
2007-01-22 23:31:40 +02:00
av_log ( s , AV_LOG_INFO , " asf_read_pts failed \n " ) ;
2005-12-22 03:10:11 +02:00
return AV_NOPTS_VALUE ;
2004-01-14 20:18:47 +02:00
}
2005-12-17 20:14:38 +02:00
2011-11-15 05:56:37 +03:00
pts = pkt - > dts ;
2004-01-14 16:45:53 +02:00
av_free_packet ( pkt ) ;
2010-03-31 15:29:58 +03:00
if ( pkt - > flags & AV_PKT_FLAG_KEY ) {
2004-01-17 20:06:52 +02:00
i = pkt - > stream_index ;
asf_st = s - > streams [ i ] - > priv_data ;
2009-06-25 02:04:05 +03:00
// assert((asf_st->packet_pos - s->data_offset) % s->packet_size == 0);
2004-04-12 19:50:03 +03:00
pos = asf_st - > packet_pos ;
2004-01-14 20:40:29 +02:00
2006-08-23 23:24:58 +03:00
av_add_index_entry ( s - > streams [ i ] , pos , pts , pkt - > size , pos - start_pos [ i ] + 1 , AVINDEX_KEYFRAME ) ;
2004-04-12 19:50:03 +03:00
start_pos [ i ] = asf_st - > packet_pos + 1 ;
2005-12-17 20:14:38 +02:00
2004-01-17 20:06:52 +02:00
if ( pkt - > stream_index = = stream_index )
break ;
}
}
* ppos = pos ;
2006-11-02 00:39:58 +02:00
//printf("found keyframe at %"PRId64" stream %d stamp:%"PRId64"\n", *ppos, stream_index, pts);
2004-01-14 16:45:53 +02:00
return pts ;
2004-01-14 15:32:49 +02:00
}
2006-08-23 20:07:01 +03:00
static void asf_build_simple_index ( AVFormatContext * s , int stream_index )
{
2009-03-18 16:03:40 +02:00
ff_asf_guid g ;
2006-08-23 20:07:01 +03:00
ASFContext * asf = s - > priv_data ;
2011-03-03 21:11:45 +02:00
int64_t current_pos = avio_tell ( s - > pb ) ;
2006-08-23 20:07:01 +03:00
2011-09-12 22:35:32 +03:00
if ( avio_seek ( s - > pb , asf - > data_object_offset + asf - > data_object_size , SEEK_SET ) < 0 ) {
asf - > index_read = - 1 ;
2011-09-12 05:06:55 +03:00
return ;
2011-09-12 22:35:32 +03:00
}
2011-09-12 05:06:55 +03:00
2010-12-26 03:26:29 +02:00
ff_get_guid ( s - > pb , & g ) ;
2010-12-03 09:49:07 +02:00
/* the data object can be followed by other top-level objects,
skip them until the simple index object is reached */
2012-04-03 10:44:10 +03:00
while ( ff_guidcmp ( & g , & ff_asf_simple_index_header ) ) {
2011-02-21 17:43:01 +02:00
int64_t gsize = avio_rl64 ( s - > pb ) ;
2010-12-03 09:49:07 +02:00
if ( gsize < 24 | | url_feof ( s - > pb ) ) {
2011-02-28 15:57:54 +02:00
avio_seek ( s - > pb , current_pos , SEEK_SET ) ;
2011-09-12 22:35:32 +03:00
asf - > index_read = - 1 ;
2010-12-03 09:49:07 +02:00
return ;
}
2011-03-15 10:14:38 +02:00
avio_skip ( s - > pb , gsize - 24 ) ;
2010-12-26 03:26:29 +02:00
ff_get_guid ( s - > pb , & g ) ;
2010-12-03 09:49:07 +02:00
}
{
2009-12-16 23:24:04 +02:00
int64_t itime , last_pos = - 1 ;
2009-04-17 15:37:39 +03:00
int pct , ict ;
2012-01-15 22:18:22 +03:00
int i ;
2011-02-21 17:43:01 +02:00
int64_t av_unused gsize = avio_rl64 ( s - > pb ) ;
2010-12-26 03:26:29 +02:00
ff_get_guid ( s - > pb , & g ) ;
2011-02-21 17:43:01 +02:00
itime = avio_rl64 ( s - > pb ) ;
pct = avio_rl32 ( s - > pb ) ;
ict = avio_rl32 ( s - > pb ) ;
2009-02-16 18:09:02 +02:00
av_log ( s , AV_LOG_DEBUG , " itime:0x% " PRIx64 " , pct:%d, ict:%d \n " , itime , pct , ict ) ;
2006-08-23 20:07:01 +03:00
for ( i = 0 ; i < ict ; i + + ) {
2011-02-21 17:43:01 +02:00
int pktnum = avio_rl32 ( s - > pb ) ;
int pktct = avio_rl16 ( s - > pb ) ;
2009-06-25 02:04:05 +03:00
int64_t pos = s - > data_offset + s - > packet_size * ( int64_t ) pktnum ;
2011-03-17 23:34:52 +02:00
int64_t index_pts = FFMAX ( av_rescale ( itime , i , 10000 ) - asf - > hdr . preroll , 0 ) ;
2006-08-23 20:07:01 +03:00
2009-12-16 23:24:04 +02:00
if ( pos ! = last_pos ) {
2011-03-17 23:34:52 +02:00
av_log ( s , AV_LOG_DEBUG , " pktnum:%d, pktct:%d pts: % " PRId64 " \n " , pktnum , pktct , index_pts ) ;
2009-06-25 02:04:05 +03:00
av_add_index_entry ( s - > streams [ stream_index ] , pos , index_pts , s - > packet_size , 0 , AVINDEX_KEYFRAME ) ;
2009-12-16 23:24:04 +02:00
last_pos = pos ;
}
2006-08-23 20:07:01 +03:00
}
2012-08-14 04:21:08 +03:00
asf - > index_read = ict > 1 ;
2006-08-23 20:07:01 +03:00
}
2011-02-28 15:57:54 +02:00
avio_seek ( s - > pb , current_pos , SEEK_SET ) ;
2006-08-23 20:07:01 +03:00
}
2004-10-11 01:05:43 +03:00
static int asf_read_seek ( AVFormatContext * s , int stream_index , int64_t pts , int flags )
2002-08-08 19:43:47 +03:00
{
2003-11-10 20:49:58 +02:00
ASFContext * asf = s - > priv_data ;
2006-08-23 20:07:01 +03:00
AVStream * st = s - > streams [ stream_index ] ;
2005-12-17 20:14:38 +02:00
2009-06-25 02:04:05 +03:00
if ( s - > packet_size < = 0 )
2004-01-14 15:32:49 +02:00
return - 1 ;
2007-12-17 11:28:46 +02:00
/* Try using the protocol's read_seek if available */
2007-12-20 02:25:18 +02:00
if ( s - > pb ) {
2011-04-12 10:37:10 +03:00
int ret = avio_seek_time ( s - > pb , stream_index , pts , flags ) ;
2007-12-17 11:28:46 +02:00
if ( ret > = 0 )
asf_reset_header ( s ) ;
2007-12-20 02:25:18 +02:00
if ( ret ! = AVERROR ( ENOSYS ) )
2007-12-20 02:26:53 +02:00
return ret ;
2007-12-17 11:28:46 +02:00
}
2006-08-23 23:24:58 +03:00
if ( ! asf - > index_read )
2006-08-23 20:07:01 +03:00
asf_build_simple_index ( s , stream_index ) ;
2011-09-12 22:35:32 +03:00
if ( ( asf - > index_read > 0 & & st - > index_entries ) ) {
2012-01-15 22:18:22 +03:00
int index = av_index_search_timestamp ( st , pts , flags ) ;
2011-05-12 11:25:54 +03:00
if ( index > = 0 ) {
2011-05-12 11:26:32 +03:00
/* find the position */
2012-01-15 22:18:22 +03:00
uint64_t pos = st - > index_entries [ index ] . pos ;
2006-08-23 20:07:01 +03:00
2011-05-12 11:26:32 +03:00
/* do the seek */
av_log ( s , AV_LOG_DEBUG , " SEEKTO: % " PRId64 " \n " , pos ) ;
2011-09-12 05:06:55 +03:00
if ( avio_seek ( s - > pb , pos , SEEK_SET ) < 0 )
return - 1 ;
2011-05-12 11:26:32 +03:00
asf_reset_header ( s ) ;
return 0 ;
2011-05-12 11:25:54 +03:00
}
2006-08-23 20:07:01 +03:00
}
2011-05-12 11:25:54 +03:00
/* no index or seeking by index failed */
2011-10-16 16:03:30 +03:00
if ( ff_seek_frame_binary ( s , stream_index , pts , flags ) < 0 )
2011-05-12 11:25:54 +03:00
return - 1 ;
2004-01-14 15:32:49 +02:00
asf_reset_header ( s ) ;
return 0 ;
2002-08-08 19:43:47 +03:00
}
2011-01-26 00:03:28 +02:00
AVInputFormat ff_asf_demuxer = {
2011-07-16 23:18:12 +03:00
. name = " asf " ,
2012-07-24 04:23:48 +03:00
. long_name = NULL_IF_CONFIG_SMALL ( " ASF (Advanced / Active Streaming Format) " ) ,
2011-07-16 23:18:12 +03:00
. priv_data_size = sizeof ( ASFContext ) ,
. read_probe = asf_probe ,
. read_header = asf_read_header ,
. read_packet = asf_read_packet ,
. read_close = asf_read_close ,
. read_seek = asf_read_seek ,
. read_timestamp = asf_read_pts ,
2012-04-06 17:50:48 +03:00
. flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH ,
2012-04-06 16:54:23 +03:00
. priv_class = & asf_class ,
2002-05-20 19:31:13 +03:00
} ;