1/* 2 * mtv demuxer 3 * Copyright (c) 2006 Reynaldo H. Verdejo Pinochet 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file libavformat/mtv.c 24 * MTV demuxer. 25 */ 26 27#include "libavutil/bswap.h" 28#include "avformat.h" 29 30#define MTV_ASUBCHUNK_DATA_SIZE 500 31#define MTV_HEADER_SIZE 512 32#define MTV_AUDIO_PADDING_SIZE 12 33#define AUDIO_SAMPLING_RATE 44100 34#define VIDEO_SID 0 35#define AUDIO_SID 1 36 37typedef struct MTVDemuxContext { 38 39 unsigned int file_size; ///< filesize, not always right 40 unsigned int segments; ///< number of 512 byte segments 41 unsigned int audio_identifier; ///< 'MP3' on all files I have seen 42 unsigned int audio_br; ///< bitrate of audio chanel (mp3) 43 unsigned int img_colorfmt; ///< frame colorfmt rgb 565/555 44 unsigned int img_bpp; ///< frame bits per pixel 45 unsigned int img_width; // 46 unsigned int img_height; // 47 unsigned int img_segment_size; ///< size of image segment 48 unsigned int video_fps; // 49 unsigned int full_segment_size; 50 51} MTVDemuxContext; 52 53static int mtv_probe(AVProbeData *p) 54{ 55 /* Magic is 'AMV' */ 56 if(*(p->buf) != 'A' || *(p->buf+1) != 'M' || *(p->buf+2) != 'V') 57 return 0; 58 59 return AVPROBE_SCORE_MAX; 60} 61 62static int mtv_read_header(AVFormatContext *s, AVFormatParameters *ap) 63{ 64 MTVDemuxContext *mtv = s->priv_data; 65 ByteIOContext *pb = s->pb; 66 AVStream *st; 67 unsigned int audio_subsegments; 68 69 url_fskip(pb, 3); 70 mtv->file_size = get_le32(pb); 71 mtv->segments = get_le32(pb); 72 url_fskip(pb, 32); 73 mtv->audio_identifier = get_le24(pb); 74 mtv->audio_br = get_le16(pb); 75 mtv->img_colorfmt = get_le24(pb); 76 mtv->img_bpp = get_byte(pb); 77 mtv->img_width = get_le16(pb); 78 mtv->img_height = get_le16(pb); 79 mtv->img_segment_size = get_le16(pb); 80 url_fskip(pb, 4); 81 audio_subsegments = get_le16(pb); 82 mtv->full_segment_size = 83 audio_subsegments * (MTV_AUDIO_PADDING_SIZE + MTV_ASUBCHUNK_DATA_SIZE) + 84 mtv->img_segment_size; 85 mtv->video_fps = (mtv->audio_br / 4) / audio_subsegments; 86 87 // FIXME Add sanity check here 88 89 // all systems go! init decoders 90 91 // video - raw rgb565 92 93 st = av_new_stream(s, VIDEO_SID); 94 if(!st) 95 return AVERROR(ENOMEM); 96 97 av_set_pts_info(st, 64, 1, mtv->video_fps); 98 st->codec->codec_type = CODEC_TYPE_VIDEO; 99 st->codec->codec_id = CODEC_ID_RAWVIDEO; 100 st->codec->codec_tag = MKTAG('R', 'G', 'B', mtv->img_bpp); 101 st->codec->width = mtv->img_width; 102 st->codec->height = mtv->img_height; 103 st->codec->bits_per_coded_sample = mtv->img_bpp; 104 st->codec->sample_rate = mtv->video_fps; 105 106 // audio - mp3 107 108 st = av_new_stream(s, AUDIO_SID); 109 if(!st) 110 return AVERROR(ENOMEM); 111 112 av_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE); 113 st->codec->codec_type = CODEC_TYPE_AUDIO; 114 st->codec->codec_id = CODEC_ID_MP3; 115 st->codec->bit_rate = mtv->audio_br; 116 st->need_parsing = AVSTREAM_PARSE_FULL; 117 118 // Jump over header 119 120 if(url_fseek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE) 121 return AVERROR(EIO); 122 123 return 0; 124 125} 126 127static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt) 128{ 129 MTVDemuxContext *mtv = s->priv_data; 130 ByteIOContext *pb = s->pb; 131 int ret; 132#ifndef WORDS_BIGENDIAN 133 int i; 134#endif 135 136 ret = 0; 137 138 if((url_ftell(pb) - s->data_offset + mtv->img_segment_size) % mtv->full_segment_size) 139 { 140 url_fskip(pb, MTV_AUDIO_PADDING_SIZE); 141 142 ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE); 143 if(ret != MTV_ASUBCHUNK_DATA_SIZE) 144 return AVERROR(EIO); 145 146 pkt->pos -= MTV_AUDIO_PADDING_SIZE; 147 pkt->stream_index = AUDIO_SID; 148 149 }else 150 { 151 ret = av_get_packet(pb, pkt, mtv->img_segment_size); 152 if(ret != mtv->img_segment_size) 153 return AVERROR(EIO); 154 155#ifndef WORDS_BIGENDIAN 156 157 /* pkt->data is GGGRRRR BBBBBGGG 158 * and we need RRRRRGGG GGGBBBBB 159 * for PIX_FMT_RGB565 so here we 160 * just swap bytes as they come 161 */ 162 163 for(i=0;i<mtv->img_segment_size/2;i++) 164 *((uint16_t *)pkt->data+i) = bswap_16(*((uint16_t *)pkt->data+i)); 165#endif 166 pkt->stream_index = VIDEO_SID; 167 } 168 169 return ret; 170} 171 172AVInputFormat mtv_demuxer = { 173 "MTV", 174 NULL_IF_CONFIG_SMALL("MTV format"), 175 sizeof(MTVDemuxContext), 176 mtv_probe, 177 mtv_read_header, 178 mtv_read_packet, 179}; 180