00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/bswap.h"
00028 #include "libavutil/intreadwrite.h"
00029 #include "avformat.h"
00030
00031 #define MTV_ASUBCHUNK_DATA_SIZE 500
00032 #define MTV_HEADER_SIZE 512
00033 #define MTV_AUDIO_PADDING_SIZE 12
00034 #define AUDIO_SAMPLING_RATE 44100
00035 #define VIDEO_SID 0
00036 #define AUDIO_SID 1
00037
00038 typedef struct MTVDemuxContext {
00039
00040 unsigned int file_size;
00041 unsigned int segments;
00042 unsigned int audio_identifier;
00043 unsigned int audio_br;
00044 unsigned int img_colorfmt;
00045 unsigned int img_bpp;
00046 unsigned int img_width;
00047 unsigned int img_height;
00048 unsigned int img_segment_size;
00049 unsigned int video_fps;
00050 unsigned int full_segment_size;
00051
00052 } MTVDemuxContext;
00053
00054 static int mtv_probe(AVProbeData *p)
00055 {
00056
00057 if(*(p->buf) != 'A' || *(p->buf+1) != 'M' || *(p->buf+2) != 'V')
00058 return 0;
00059
00060
00061 if(!(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54])))
00062 return 0;
00063
00064
00065 if(!AV_RL16(&p->buf[52]) || !AV_RL16(&p->buf[54]))
00066 {
00067 if(!!AV_RL16(&p->buf[56]))
00068 return AVPROBE_SCORE_MAX/2;
00069 else
00070 return 0;
00071 }
00072
00073 if(p->buf[51] != 16)
00074 return AVPROBE_SCORE_MAX/4;
00075
00076 return AVPROBE_SCORE_MAX;
00077 }
00078
00079 static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap)
00080 {
00081 MTVDemuxContext *mtv = s->priv_data;
00082 ByteIOContext *pb = s->pb;
00083 AVStream *st;
00084 unsigned int audio_subsegments;
00085
00086 url_fskip(pb, 3);
00087 mtv->file_size = get_le32(pb);
00088 mtv->segments = get_le32(pb);
00089 url_fskip(pb, 32);
00090 mtv->audio_identifier = get_le24(pb);
00091 mtv->audio_br = get_le16(pb);
00092 mtv->img_colorfmt = get_le24(pb);
00093 mtv->img_bpp = get_byte(pb);
00094 mtv->img_width = get_le16(pb);
00095 mtv->img_height = get_le16(pb);
00096 mtv->img_segment_size = get_le16(pb);
00097
00098
00099
00100 if(!mtv->img_width)
00101 mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3)
00102 / mtv->img_height;
00103
00104 if(!mtv->img_height)
00105 mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3)
00106 / mtv->img_width;
00107
00108 url_fskip(pb, 4);
00109 audio_subsegments = get_le16(pb);
00110 mtv->full_segment_size =
00111 audio_subsegments * (MTV_AUDIO_PADDING_SIZE + MTV_ASUBCHUNK_DATA_SIZE) +
00112 mtv->img_segment_size;
00113 mtv->video_fps = (mtv->audio_br / 4) / audio_subsegments;
00114
00115
00116
00117
00118
00119
00120
00121 st = av_new_stream(s, VIDEO_SID);
00122 if(!st)
00123 return AVERROR(ENOMEM);
00124
00125 av_set_pts_info(st, 64, 1, mtv->video_fps);
00126 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00127 st->codec->codec_id = CODEC_ID_RAWVIDEO;
00128 st->codec->codec_tag = MKTAG('R', 'G', 'B', mtv->img_bpp);
00129 st->codec->width = mtv->img_width;
00130 st->codec->height = mtv->img_height;
00131 st->codec->bits_per_coded_sample = mtv->img_bpp;
00132 st->codec->sample_rate = mtv->video_fps;
00133 st->codec->extradata = av_strdup("BottomUp");
00134 st->codec->extradata_size = 9;
00135
00136
00137
00138 st = av_new_stream(s, AUDIO_SID);
00139 if(!st)
00140 return AVERROR(ENOMEM);
00141
00142 av_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE);
00143 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00144 st->codec->codec_id = CODEC_ID_MP3;
00145 st->codec->bit_rate = mtv->audio_br;
00146 st->need_parsing = AVSTREAM_PARSE_FULL;
00147
00148
00149
00150 if(url_fseek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE)
00151 return AVERROR(EIO);
00152
00153 return 0;
00154
00155 }
00156
00157 static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt)
00158 {
00159 MTVDemuxContext *mtv = s->priv_data;
00160 ByteIOContext *pb = s->pb;
00161 int ret;
00162 #if !HAVE_BIGENDIAN
00163 int i;
00164 #endif
00165
00166 if((url_ftell(pb) - s->data_offset + mtv->img_segment_size) % mtv->full_segment_size)
00167 {
00168 url_fskip(pb, MTV_AUDIO_PADDING_SIZE);
00169
00170 ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE);
00171 if(ret < 0)
00172 return ret;
00173
00174 pkt->pos -= MTV_AUDIO_PADDING_SIZE;
00175 pkt->stream_index = AUDIO_SID;
00176
00177 }else
00178 {
00179 ret = av_get_packet(pb, pkt, mtv->img_segment_size);
00180 if(ret < 0)
00181 return ret;
00182
00183 #if !HAVE_BIGENDIAN
00184
00185
00186
00187
00188
00189
00190
00191 for(i=0;i<mtv->img_segment_size/2;i++)
00192 *((uint16_t *)pkt->data+i) = bswap_16(*((uint16_t *)pkt->data+i));
00193 #endif
00194 pkt->stream_index = VIDEO_SID;
00195 }
00196
00197 return ret;
00198 }
00199
00200 AVInputFormat mtv_demuxer = {
00201 "MTV",
00202 NULL_IF_CONFIG_SMALL("MTV format"),
00203 sizeof(MTVDemuxContext),
00204 mtv_probe,
00205 mtv_read_header,
00206 mtv_read_packet,
00207 };