00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00032 #include "avformat.h"
00033
00034
00035
00036 #define RIFF_TAG MKTAG('R', 'I', 'F', 'F')
00037 #define CDXA_TAG MKTAG('C', 'D', 'X', 'A')
00038
00039 #define RAW_CD_SECTOR_SIZE 2352
00040 #define RAW_CD_SECTOR_DATA_SIZE 2304
00041 #define VIDEO_DATA_CHUNK_SIZE 0x7E0
00042 #define VIDEO_DATA_HEADER_SIZE 0x38
00043 #define RIFF_HEADER_SIZE 0x2C
00044
00045 #define CDXA_TYPE_MASK 0x0E
00046 #define CDXA_TYPE_DATA 0x08
00047 #define CDXA_TYPE_AUDIO 0x04
00048 #define CDXA_TYPE_VIDEO 0x02
00049
00050 #define STR_MAGIC (0x80010160)
00051
00052 typedef struct StrChannel {
00053
00054 int type;
00055 #define STR_AUDIO 0
00056 #define STR_VIDEO 1
00057
00058
00059 int width;
00060 int height;
00061 int video_stream_index;
00062
00063
00064 int sample_rate;
00065 int channels;
00066 int bits;
00067 int audio_stream_index;
00068 } StrChannel;
00069
00070 typedef struct StrDemuxContext {
00071
00072
00073 StrChannel channels[32];
00074
00075
00076 int video_channel;
00077 int audio_channel;
00078
00079 int64_t pts;
00080
00081 unsigned char *video_chunk;
00082 AVPacket tmp_pkt;
00083 } StrDemuxContext;
00084
00085 static const char sync_header[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00};
00086
00087 static int str_probe(AVProbeData *p)
00088 {
00089 int start;
00090
00091
00092 if (p->buf_size < 0x38)
00093 return 0;
00094
00095 if ((AV_RL32(&p->buf[0]) == RIFF_TAG) &&
00096 (AV_RL32(&p->buf[8]) == CDXA_TAG)) {
00097
00098
00099 start = RIFF_HEADER_SIZE;
00100 } else
00101 start = 0;
00102
00103
00104 if (memcmp(p->buf+start,sync_header,sizeof(sync_header)))
00105 return 0;
00106
00107
00108
00109 return 50;
00110 }
00111
00112 #if 0
00113 static void dump(unsigned char *buf,size_t len)
00114 {
00115 int i;
00116 for(i=0;i<len;i++) {
00117 if ((i&15)==0) av_log(NULL, AV_LOG_DEBUG, "%04x ",i);
00118 av_log(NULL, AV_LOG_DEBUG, "%02x ",buf[i]);
00119 if ((i&15)==15) av_log(NULL, AV_LOG_DEBUG, "\n");
00120 }
00121 av_log(NULL, AV_LOG_DEBUG, "\n");
00122 }
00123 #endif
00124
00125 static int str_read_header(AVFormatContext *s,
00126 AVFormatParameters *ap)
00127 {
00128 ByteIOContext *pb = s->pb;
00129 StrDemuxContext *str = s->priv_data;
00130 AVStream *st;
00131 unsigned char sector[RAW_CD_SECTOR_SIZE];
00132 int start;
00133 int i;
00134 int channel;
00135
00136
00137 str->pts = 0;
00138 str->audio_channel = -1;
00139 str->video_channel = -1;
00140 str->video_chunk = NULL;
00141
00142
00143
00144 if (get_buffer(pb, sector, RIFF_HEADER_SIZE) != RIFF_HEADER_SIZE)
00145 return AVERROR(EIO);
00146 if (AV_RL32(§or[0]) == RIFF_TAG)
00147 start = RIFF_HEADER_SIZE;
00148 else
00149 start = 0;
00150
00151 url_fseek(pb, start, SEEK_SET);
00152
00153
00154 for (i = 0; i < 32; i++) {
00155 if (get_buffer(pb, sector, RAW_CD_SECTOR_SIZE) != RAW_CD_SECTOR_SIZE)
00156 return AVERROR(EIO);
00157
00158
00159
00160 channel = sector[0x11];
00161 if (channel >= 32)
00162 return AVERROR_INVALIDDATA;
00163
00164 switch (sector[0x12] & CDXA_TYPE_MASK) {
00165
00166 case CDXA_TYPE_DATA:
00167 case CDXA_TYPE_VIDEO:
00168
00169 if (str->video_channel == -1) {
00170
00171 if (AV_RL32(§or[0x18]) != STR_MAGIC)
00172 break;
00173 str->video_channel = channel;
00174 str->channels[channel].type = STR_VIDEO;
00175 str->channels[channel].width = AV_RL16(§or[0x28]);
00176 str->channels[channel].height = AV_RL16(§or[0x2A]);
00177
00178
00179 st = av_new_stream(s, 0);
00180 if (!st)
00181 return AVERROR(ENOMEM);
00182 av_set_pts_info(st, 64, 1, 15);
00183
00184 str->channels[channel].video_stream_index = st->index;
00185
00186 st->codec->codec_type = CODEC_TYPE_VIDEO;
00187 st->codec->codec_id = CODEC_ID_MDEC;
00188 st->codec->codec_tag = 0;
00189 st->codec->width = str->channels[channel].width;
00190 st->codec->height = str->channels[channel].height;
00191 }
00192 break;
00193
00194 case CDXA_TYPE_AUDIO:
00195
00196 if (str->audio_channel == -1) {
00197 int fmt;
00198 str->audio_channel = channel;
00199 str->channels[channel].type = STR_AUDIO;
00200 str->channels[channel].channels =
00201 (sector[0x13] & 0x01) ? 2 : 1;
00202 str->channels[channel].sample_rate =
00203 (sector[0x13] & 0x04) ? 18900 : 37800;
00204 str->channels[channel].bits =
00205 (sector[0x13] & 0x10) ? 8 : 4;
00206
00207
00208 st = av_new_stream(s, 0);
00209 if (!st)
00210 return AVERROR(ENOMEM);
00211 av_set_pts_info(st, 64, 128, str->channels[channel].sample_rate);
00212
00213 str->channels[channel].audio_stream_index = st->index;
00214
00215 fmt = sector[0x13];
00216 st->codec->codec_type = CODEC_TYPE_AUDIO;
00217 st->codec->codec_id = CODEC_ID_ADPCM_XA;
00218 st->codec->codec_tag = 0;
00219 st->codec->channels = (fmt&1)?2:1;
00220 st->codec->sample_rate = (fmt&4)?18900:37800;
00221
00222 st->codec->block_align = 128;
00223 }
00224 break;
00225
00226 default:
00227
00228 break;
00229 }
00230 }
00231
00232 if (str->video_channel != -1)
00233 av_log (s, AV_LOG_DEBUG, " video channel = %d, %d x %d %d\n", str->video_channel,
00234 str->channels[str->video_channel].width,
00235 str->channels[str->video_channel].height,str->channels[str->video_channel].video_stream_index);
00236 if (str->audio_channel != -1)
00237 av_log (s, AV_LOG_DEBUG, " audio channel = %d, %d Hz, %d channels, %d bits/sample %d\n",
00238 str->audio_channel,
00239 str->channels[str->audio_channel].sample_rate,
00240 str->channels[str->audio_channel].channels,
00241 str->channels[str->audio_channel].bits,str->channels[str->audio_channel].audio_stream_index);
00242
00243
00244 url_fseek(pb, start, SEEK_SET);
00245
00246 return 0;
00247 }
00248
00249 static int str_read_packet(AVFormatContext *s,
00250 AVPacket *ret_pkt)
00251 {
00252 ByteIOContext *pb = s->pb;
00253 StrDemuxContext *str = s->priv_data;
00254 unsigned char sector[RAW_CD_SECTOR_SIZE];
00255 int channel;
00256 int packet_read = 0;
00257 int ret = 0;
00258 AVPacket *pkt;
00259
00260 while (!packet_read) {
00261
00262 if (get_buffer(pb, sector, RAW_CD_SECTOR_SIZE) != RAW_CD_SECTOR_SIZE)
00263 return AVERROR(EIO);
00264
00265 channel = sector[0x11];
00266 if (channel >= 32)
00267 return AVERROR_INVALIDDATA;
00268
00269 switch (sector[0x12] & CDXA_TYPE_MASK) {
00270
00271 case CDXA_TYPE_DATA:
00272 case CDXA_TYPE_VIDEO:
00273
00274 if (channel == str->video_channel) {
00275
00276 int current_sector = AV_RL16(§or[0x1C]);
00277 int sector_count = AV_RL16(§or[0x1E]);
00278 int frame_size = AV_RL32(§or[0x24]);
00279
00280 if(!( frame_size>=0
00281 && current_sector < sector_count
00282 && sector_count*VIDEO_DATA_CHUNK_SIZE >=frame_size)){
00283 av_log(s, AV_LOG_ERROR, "Invalid parameters %d %d %d\n", current_sector, sector_count, frame_size);
00284 return AVERROR_INVALIDDATA;
00285 }
00286
00287
00288
00289 pkt = &str->tmp_pkt;
00290
00291 if(pkt->size != sector_count*VIDEO_DATA_CHUNK_SIZE){
00292 if(pkt->data)
00293 av_log(s, AV_LOG_ERROR, "missmatching sector_count\n");
00294 av_free_packet(pkt);
00295 if (av_new_packet(pkt, sector_count*VIDEO_DATA_CHUNK_SIZE))
00296 return AVERROR(EIO);
00297
00298 pkt->pos= url_ftell(pb) - RAW_CD_SECTOR_SIZE;
00299 pkt->stream_index =
00300 str->channels[channel].video_stream_index;
00301
00302
00303
00304
00305 if (str->audio_channel != -1)
00306 str->pts += (90000 / 15);
00307 }
00308
00309 memcpy(pkt->data + current_sector*VIDEO_DATA_CHUNK_SIZE,
00310 sector + VIDEO_DATA_HEADER_SIZE,
00311 VIDEO_DATA_CHUNK_SIZE);
00312
00313 if (current_sector == sector_count-1) {
00314 pkt->size= frame_size;
00315 *ret_pkt = *pkt;
00316 pkt->data= NULL;
00317 pkt->size= -1;
00318 return 0;
00319 }
00320
00321 }
00322 break;
00323
00324 case CDXA_TYPE_AUDIO:
00325 #ifdef PRINTSTUFF
00326 printf (" dropping audio sector\n");
00327 #endif
00328 #if 1
00329
00330 if (channel == str->audio_channel) {
00331 pkt = ret_pkt;
00332 if (av_new_packet(pkt, 2304))
00333 return AVERROR(EIO);
00334 memcpy(pkt->data,sector+24,2304);
00335
00336 pkt->stream_index =
00337 str->channels[channel].audio_stream_index;
00338
00339 return 0;
00340 }
00341 #endif
00342 break;
00343 default:
00344
00345 #ifdef PRINTSTUFF
00346 printf (" dropping other sector\n");
00347 #endif
00348 break;
00349 }
00350
00351 if (url_feof(pb))
00352 return AVERROR(EIO);
00353 }
00354
00355 return ret;
00356 }
00357
00358 static int str_read_close(AVFormatContext *s)
00359 {
00360 StrDemuxContext *str = s->priv_data;
00361
00362 av_free(str->video_chunk);
00363
00364 return 0;
00365 }
00366
00367 AVInputFormat str_demuxer = {
00368 "psxstr",
00369 "Sony Playstation STR format",
00370 sizeof(StrDemuxContext),
00371 str_probe,
00372 str_read_header,
00373 str_read_packet,
00374 str_read_close,
00375 };