Libav
|
00001 /* 00002 * mtv demuxer 00003 * Copyright (c) 2006 Reynaldo H. Verdejo Pinochet 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 /* Magic is 'AMV' */ 00057 if(*(p->buf) != 'A' || *(p->buf+1) != 'M' || *(p->buf+2) != 'V') 00058 return 0; 00059 00060 /* Check for nonzero in bpp and (width|height) header fields */ 00061 if(!(p->buf[51] && AV_RL16(&p->buf[52]) | AV_RL16(&p->buf[54]))) 00062 return 0; 00063 00064 /* If width or height are 0 then imagesize header field should not */ 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; // But we are going to assume 16bpp anyway .. 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 /* Calculate width and height if missing from header */ 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 // FIXME Add sanity check here 00116 00117 // all systems go! init decoders 00118 00119 // video - raw rgb565 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->pix_fmt = PIX_FMT_RGB565; 00129 st->codec->width = mtv->img_width; 00130 st->codec->height = mtv->img_height; 00131 st->codec->sample_rate = mtv->video_fps; 00132 st->codec->extradata = av_strdup("BottomUp"); 00133 st->codec->extradata_size = 9; 00134 00135 // audio - mp3 00136 00137 st = av_new_stream(s, AUDIO_SID); 00138 if(!st) 00139 return AVERROR(ENOMEM); 00140 00141 av_set_pts_info(st, 64, 1, AUDIO_SAMPLING_RATE); 00142 st->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00143 st->codec->codec_id = CODEC_ID_MP3; 00144 st->codec->bit_rate = mtv->audio_br; 00145 st->need_parsing = AVSTREAM_PARSE_FULL; 00146 00147 // Jump over header 00148 00149 if(url_fseek(pb, MTV_HEADER_SIZE, SEEK_SET) != MTV_HEADER_SIZE) 00150 return AVERROR(EIO); 00151 00152 return 0; 00153 00154 } 00155 00156 static int mtv_read_packet(AVFormatContext *s, AVPacket *pkt) 00157 { 00158 MTVDemuxContext *mtv = s->priv_data; 00159 ByteIOContext *pb = s->pb; 00160 int ret; 00161 #if !HAVE_BIGENDIAN 00162 int i; 00163 #endif 00164 00165 if((url_ftell(pb) - s->data_offset + mtv->img_segment_size) % mtv->full_segment_size) 00166 { 00167 url_fskip(pb, MTV_AUDIO_PADDING_SIZE); 00168 00169 ret = av_get_packet(pb, pkt, MTV_ASUBCHUNK_DATA_SIZE); 00170 if(ret < 0) 00171 return ret; 00172 00173 pkt->pos -= MTV_AUDIO_PADDING_SIZE; 00174 pkt->stream_index = AUDIO_SID; 00175 00176 }else 00177 { 00178 ret = av_get_packet(pb, pkt, mtv->img_segment_size); 00179 if(ret < 0) 00180 return ret; 00181 00182 #if !HAVE_BIGENDIAN 00183 00184 /* pkt->data is GGGRRRR BBBBBGGG 00185 * and we need RRRRRGGG GGGBBBBB 00186 * for PIX_FMT_RGB565 so here we 00187 * just swap bytes as they come 00188 */ 00189 00190 for(i=0;i<mtv->img_segment_size/2;i++) 00191 *((uint16_t *)pkt->data+i) = bswap_16(*((uint16_t *)pkt->data+i)); 00192 #endif 00193 pkt->stream_index = VIDEO_SID; 00194 } 00195 00196 return ret; 00197 } 00198 00199 AVInputFormat mtv_demuxer = { 00200 "MTV", 00201 NULL_IF_CONFIG_SMALL("MTV format"), 00202 sizeof(MTVDemuxContext), 00203 mtv_probe, 00204 mtv_read_header, 00205 mtv_read_packet, 00206 };