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 #include "internal.h"
00031
00032 #define MTV_ASUBCHUNK_DATA_SIZE 500
00033 #define MTV_HEADER_SIZE 512
00034 #define MTV_AUDIO_PADDING_SIZE 12
00035 #define AUDIO_SAMPLING_RATE 44100
00036
00037 typedef struct MTVDemuxContext {
00038
00039 unsigned int file_size;
00040 unsigned int segments;
00041 unsigned int audio_identifier;
00042 unsigned int audio_br;
00043 unsigned int img_colorfmt;
00044 unsigned int img_bpp;
00045 unsigned int img_width;
00046 unsigned int img_height;
00047 unsigned int img_segment_size;
00048 unsigned int video_fps;
00049 unsigned int full_segment_size;
00050
00051 } MTVDemuxContext;
00052
00053 static int mtv_probe(AVProbeData *p)
00054 {
00055
00056 if(*(p->buf) != 'A' || *(p->buf+1) != 'M' || *(p->buf+2) != 'V')
00057 return 0;
00058
00059
00060 if(!(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54])))
00061 return 0;
00062
00063
00064 if(!AV_RL16(&p->buf[52]) || !AV_RL16(&p->buf[54]))
00065 {
00066 if(!!AV_RL16(&p->buf[56]))
00067 return AVPROBE_SCORE_MAX/2;
00068 else
00069 return 0;
00070 }
00071
00072 if(p->buf[51] != 16)
00073 return AVPROBE_SCORE_MAX/4;
00074
00075 return AVPROBE_SCORE_MAX;
00076 }
00077
00078 static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap)
00079 {
00080 MTVDemuxContext *mtv = s->priv_data;
00081 AVIOContext *pb = s->pb;
00082 AVStream *st;
00083 unsigned int audio_subsegments;
00084
00085 avio_skip(pb, 3);
00086 mtv->file_size = avio_rl32(pb);
00087 mtv->segments = avio_rl32(pb);
00088 avio_skip(pb, 32);
00089 mtv->audio_identifier = avio_rl24(pb);
00090 mtv->audio_br = avio_rl16(pb);
00091 mtv->img_colorfmt = avio_rl24(pb);
00092 mtv->img_bpp = avio_r8(pb);
00093 mtv->img_width = avio_rl16(pb);
00094 mtv->img_height = avio_rl16(pb);
00095 mtv->img_segment_size = avio_rl16(pb);
00096
00097
00098
00099 if(mtv->img_bpp>>3){
00100 if(!mtv->img_width && mtv->img_height)
00101 mtv->img_width=mtv->img_segment_size / (mtv->img_bpp>>3)
00102 / mtv->img_height;
00103
00104 if(!mtv->img_height && mtv->img_width)
00105 mtv->img_height=mtv->img_segment_size / (mtv->img_bpp>>3)
00106 / mtv->img_width;
00107 }
00108 if(!mtv->img_height || !mtv->img_width){
00109 av_log(s, AV_LOG_ERROR, "width or height is invalid and I cannot calculate them from other information\n");
00110 return AVERROR(EINVAL);
00111 }
00112
00113 avio_skip(pb, 4);
00114 audio_subsegments = avio_rl16(pb);
00115 if(!audio_subsegments){
00116 av_log(s, AV_LOG_ERROR, "audio_subsegments is 0\n");
00117 return AVERROR(EINVAL);
00118 }
00119 mtv->full_segment_size =
00120 audio_subsegments * (MTV_AUDIO_PADDING_SIZE + MTV_ASUBCHUNK_DATA_SIZE) +
00121 mtv->img_segment_size;
00122 mtv->video_fps = (mtv->audio_br / 4) / audio_subsegments;
00123
00124
00125
00126
00127
00128
00129
00130 st = avformat_new_stream(s, NULL);
00131 if(!st)
00132 return AVERROR(ENOMEM);
00133
00134 avpriv_set_pts_info(st, 64, 1, mtv->video_fps);
00135 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00136 st->codec->codec_id = CODEC_ID_RAWVIDEO;
00137 st->codec->pix_fmt = PIX_FMT_RGB565;
00138 st->codec->width = mtv->img_width;
00139 st->codec->height = mtv->img_height;
00140 st->codec->sample_rate = mtv->video_fps;
00141 st->codec->extradata = av_strdup("BottomUp");
00142 st->codec->extradata_size = 9;
00143
00144
00145
00146 st = avformat_new_stream(s, NULL);
00147 if(!st)
00148 return AVERROR(ENOMEM);
00149
00150 avpriv_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE);
00151 st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00152 st->codec->codec_id = CODEC_ID_MP3;
00153 st->codec->bit_rate = mtv->audio_br;
00154 st->need_parsing = AVSTREAM_PARSE_FULL;
00155
00156
00157
00158 if(avio_seek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE)
00159 return AVERROR(EIO);
00160
00161 return 0;
00162
00163 }
00164
00165 static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt)
00166 {
00167 MTVDemuxContext *mtv = s->priv_data;
00168 AVIOContext *pb = s->pb;
00169 int ret;
00170 #if !HAVE_BIGENDIAN
00171 int i;
00172 #endif
00173
00174 if((avio_tell(pb) - s->data_offset + mtv->img_segment_size) % mtv->full_segment_size)
00175 {
00176 avio_skip(pb, MTV_AUDIO_PADDING_SIZE);
00177
00178 ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE);
00179 if(ret < 0)
00180 return ret;
00181
00182 pkt->pos -= MTV_AUDIO_PADDING_SIZE;
00183 pkt->stream_index = 1;
00184
00185 }else
00186 {
00187 ret = av_get_packet(pb, pkt, mtv->img_segment_size);
00188 if(ret < 0)
00189 return ret;
00190
00191 #if !HAVE_BIGENDIAN
00192
00193
00194
00195
00196
00197
00198
00199 for(i=0;i<ret/2;i++)
00200 *((uint16_t *)pkt->data+i) = av_bswap16(*((uint16_t *)pkt->data+i));
00201 #endif
00202 pkt->stream_index = 0;
00203 }
00204
00205 return ret;
00206 }
00207
00208 AVInputFormat ff_mtv_demuxer = {
00209 .name = "MTV",
00210 .long_name = NULL_IF_CONFIG_SMALL("MTV format"),
00211 .priv_data_size = sizeof(MTVDemuxContext),
00212 .read_probe = mtv_probe,
00213 .read_header = mtv_read_header,
00214 .read_packet = mtv_read_packet,
00215 };