Libav
|
00001 /* 00002 * R3D REDCODE demuxer 00003 * Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot com> 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 00022 //#define DEBUG 00023 00024 #include "libavutil/intreadwrite.h" 00025 #include "avformat.h" 00026 00027 typedef struct { 00028 unsigned video_offsets_count; 00029 unsigned *video_offsets; 00030 unsigned rdvo_offset; 00031 } R3DContext; 00032 00033 typedef struct { 00034 unsigned size; 00035 uint32_t tag; 00036 uint64_t offset; 00037 } Atom; 00038 00039 static int read_atom(AVFormatContext *s, Atom *atom) 00040 { 00041 atom->offset = url_ftell(s->pb); 00042 atom->size = get_be32(s->pb); 00043 if (atom->size < 8) 00044 return -1; 00045 atom->tag = get_le32(s->pb); 00046 dprintf(s, "atom %d %.4s offset %#llx\n", 00047 atom->size, (char*)&atom->tag, atom->offset); 00048 return atom->size; 00049 } 00050 00051 static int r3d_read_red1(AVFormatContext *s) 00052 { 00053 AVStream *st = av_new_stream(s, 0); 00054 char filename[258]; 00055 int tmp, tmp2; 00056 00057 if (!st) 00058 return AVERROR(ENOMEM); 00059 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 00060 st->codec->codec_id = CODEC_ID_JPEG2000; 00061 00062 tmp = get_byte(s->pb); // major version 00063 tmp2 = get_byte(s->pb); // minor version 00064 dprintf(s, "version %d.%d\n", tmp, tmp2); 00065 00066 tmp = get_be16(s->pb); // unknown 00067 dprintf(s, "unknown1 %d\n", tmp); 00068 00069 tmp = get_be32(s->pb); 00070 av_set_pts_info(st, 32, 1, tmp); 00071 00072 tmp = get_be32(s->pb); // filenum 00073 dprintf(s, "filenum %d\n", tmp); 00074 00075 url_fskip(s->pb, 32); // unknown 00076 00077 st->codec->width = get_be32(s->pb); 00078 st->codec->height = get_be32(s->pb); 00079 00080 tmp = get_be16(s->pb); // unknown 00081 dprintf(s, "unknown2 %d\n", tmp); 00082 00083 st->codec->time_base.den = get_be16(s->pb); 00084 st->codec->time_base.num = get_be16(s->pb); 00085 00086 tmp = get_byte(s->pb); // audio channels 00087 dprintf(s, "audio channels %d\n", tmp); 00088 if (tmp > 0) { 00089 AVStream *ast = av_new_stream(s, 1); 00090 if (!ast) 00091 return AVERROR(ENOMEM); 00092 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; 00093 ast->codec->codec_id = CODEC_ID_PCM_S32BE; 00094 ast->codec->channels = tmp; 00095 av_set_pts_info(ast, 32, 1, st->time_base.den); 00096 } 00097 00098 get_buffer(s->pb, filename, 257); 00099 filename[sizeof(filename)-1] = 0; 00100 av_metadata_set2(&st->metadata, "filename", filename, 0); 00101 00102 dprintf(s, "filename %s\n", filename); 00103 dprintf(s, "resolution %dx%d\n", st->codec->width, st->codec->height); 00104 dprintf(s, "timescale %d\n", st->time_base.den); 00105 dprintf(s, "frame rate %d/%d\n", 00106 st->codec->time_base.num, st->codec->time_base.den); 00107 00108 return 0; 00109 } 00110 00111 static int r3d_read_rdvo(AVFormatContext *s, Atom *atom) 00112 { 00113 R3DContext *r3d = s->priv_data; 00114 AVStream *st = s->streams[0]; 00115 int i; 00116 00117 r3d->video_offsets_count = (atom->size - 8) / 4; 00118 r3d->video_offsets = av_malloc(atom->size); 00119 if (!r3d->video_offsets) 00120 return AVERROR(ENOMEM); 00121 00122 for (i = 0; i < r3d->video_offsets_count; i++) { 00123 r3d->video_offsets[i] = get_be32(s->pb); 00124 if (!r3d->video_offsets[i]) { 00125 r3d->video_offsets_count = i; 00126 break; 00127 } 00128 dprintf(s, "video offset %d: %#x\n", i, r3d->video_offsets[i]); 00129 } 00130 00131 if (st->codec->time_base.den) 00132 st->duration = (uint64_t)r3d->video_offsets_count* 00133 st->time_base.den*st->codec->time_base.num/st->codec->time_base.den; 00134 dprintf(s, "duration %lld\n", st->duration); 00135 00136 return 0; 00137 } 00138 00139 static void r3d_read_reos(AVFormatContext *s) 00140 { 00141 R3DContext *r3d = s->priv_data; 00142 int tmp; 00143 00144 r3d->rdvo_offset = get_be32(s->pb); 00145 get_be32(s->pb); // rdvs offset 00146 get_be32(s->pb); // rdao offset 00147 get_be32(s->pb); // rdas offset 00148 00149 tmp = get_be32(s->pb); 00150 dprintf(s, "num video chunks %d\n", tmp); 00151 00152 tmp = get_be32(s->pb); 00153 dprintf(s, "num audio chunks %d\n", tmp); 00154 00155 url_fskip(s->pb, 6*4); 00156 } 00157 00158 static int r3d_read_header(AVFormatContext *s, AVFormatParameters *ap) 00159 { 00160 R3DContext *r3d = s->priv_data; 00161 Atom atom; 00162 int ret; 00163 00164 if (read_atom(s, &atom) < 0) { 00165 av_log(s, AV_LOG_ERROR, "error reading atom\n"); 00166 return -1; 00167 } 00168 if (atom.tag == MKTAG('R','E','D','1')) { 00169 if ((ret = r3d_read_red1(s)) < 0) { 00170 av_log(s, AV_LOG_ERROR, "error parsing 'red1' atom\n"); 00171 return ret; 00172 } 00173 } else { 00174 av_log(s, AV_LOG_ERROR, "could not find 'red1' atom\n"); 00175 return -1; 00176 } 00177 00178 s->data_offset = url_ftell(s->pb); 00179 dprintf(s, "data offset %#llx\n", s->data_offset); 00180 if (url_is_streamed(s->pb)) 00181 return 0; 00182 // find REOB/REOF/REOS to load index 00183 url_fseek(s->pb, url_fsize(s->pb)-48-8, SEEK_SET); 00184 if (read_atom(s, &atom) < 0) 00185 av_log(s, AV_LOG_ERROR, "error reading end atom\n"); 00186 00187 if (atom.tag != MKTAG('R','E','O','B') && 00188 atom.tag != MKTAG('R','E','O','F') && 00189 atom.tag != MKTAG('R','E','O','S')) 00190 goto out; 00191 00192 r3d_read_reos(s); 00193 00194 if (r3d->rdvo_offset) { 00195 url_fseek(s->pb, r3d->rdvo_offset, SEEK_SET); 00196 if (read_atom(s, &atom) < 0) 00197 av_log(s, AV_LOG_ERROR, "error reading 'rdvo' atom\n"); 00198 if (atom.tag == MKTAG('R','D','V','O')) { 00199 if (r3d_read_rdvo(s, &atom) < 0) 00200 av_log(s, AV_LOG_ERROR, "error parsing 'rdvo' atom\n"); 00201 } 00202 } 00203 00204 out: 00205 url_fseek(s->pb, s->data_offset, SEEK_SET); 00206 return 0; 00207 } 00208 00209 static int r3d_read_redv(AVFormatContext *s, AVPacket *pkt, Atom *atom) 00210 { 00211 AVStream *st = s->streams[0]; 00212 int tmp, tmp2; 00213 uint64_t pos = url_ftell(s->pb); 00214 unsigned dts; 00215 int ret; 00216 00217 dts = get_be32(s->pb); 00218 00219 tmp = get_be32(s->pb); 00220 dprintf(s, "frame num %d\n", tmp); 00221 00222 tmp = get_byte(s->pb); // major version 00223 tmp2 = get_byte(s->pb); // minor version 00224 dprintf(s, "version %d.%d\n", tmp, tmp2); 00225 00226 tmp = get_be16(s->pb); // unknown 00227 dprintf(s, "unknown %d\n", tmp); 00228 00229 if (tmp > 4) { 00230 tmp = get_be16(s->pb); // unknown 00231 dprintf(s, "unknown %d\n", tmp); 00232 00233 tmp = get_be16(s->pb); // unknown 00234 dprintf(s, "unknown %d\n", tmp); 00235 00236 tmp = get_be32(s->pb); 00237 dprintf(s, "width %d\n", tmp); 00238 tmp = get_be32(s->pb); 00239 dprintf(s, "height %d\n", tmp); 00240 00241 tmp = get_be32(s->pb); 00242 dprintf(s, "metadata len %d\n", tmp); 00243 } 00244 tmp = atom->size - 8 - (url_ftell(s->pb) - pos); 00245 if (tmp < 0) 00246 return -1; 00247 ret = av_get_packet(s->pb, pkt, tmp); 00248 if (ret < 0) { 00249 av_log(s, AV_LOG_ERROR, "error reading video packet\n"); 00250 return -1; 00251 } 00252 00253 pkt->stream_index = 0; 00254 pkt->dts = dts; 00255 if (st->codec->time_base.den) 00256 pkt->duration = (uint64_t)st->time_base.den* 00257 st->codec->time_base.num/st->codec->time_base.den; 00258 dprintf(s, "pkt dts %lld duration %d\n", pkt->dts, pkt->duration); 00259 00260 return 0; 00261 } 00262 00263 static int r3d_read_reda(AVFormatContext *s, AVPacket *pkt, Atom *atom) 00264 { 00265 AVStream *st = s->streams[1]; 00266 int tmp, tmp2, samples, size; 00267 uint64_t pos = url_ftell(s->pb); 00268 unsigned dts; 00269 int ret; 00270 00271 dts = get_be32(s->pb); 00272 00273 st->codec->sample_rate = get_be32(s->pb); 00274 00275 samples = get_be32(s->pb); 00276 00277 tmp = get_be32(s->pb); 00278 dprintf(s, "packet num %d\n", tmp); 00279 00280 tmp = get_be16(s->pb); // unkown 00281 dprintf(s, "unknown %d\n", tmp); 00282 00283 tmp = get_byte(s->pb); // major version 00284 tmp2 = get_byte(s->pb); // minor version 00285 dprintf(s, "version %d.%d\n", tmp, tmp2); 00286 00287 tmp = get_be32(s->pb); // unknown 00288 dprintf(s, "unknown %d\n", tmp); 00289 00290 size = atom->size - 8 - (url_ftell(s->pb) - pos); 00291 if (size < 0) 00292 return -1; 00293 ret = av_get_packet(s->pb, pkt, size); 00294 if (ret < 0) { 00295 av_log(s, AV_LOG_ERROR, "error reading audio packet\n"); 00296 return ret; 00297 } 00298 00299 pkt->stream_index = 1; 00300 pkt->dts = dts; 00301 pkt->duration = av_rescale(samples, st->time_base.den, st->codec->sample_rate); 00302 dprintf(s, "pkt dts %lld duration %d samples %d sample rate %d\n", 00303 pkt->dts, pkt->duration, samples, st->codec->sample_rate); 00304 00305 return 0; 00306 } 00307 00308 static int r3d_read_packet(AVFormatContext *s, AVPacket *pkt) 00309 { 00310 Atom atom; 00311 int err = 0; 00312 00313 while (!err) { 00314 if (read_atom(s, &atom) < 0) { 00315 err = -1; 00316 break; 00317 } 00318 switch (atom.tag) { 00319 case MKTAG('R','E','D','V'): 00320 if (s->streams[0]->discard == AVDISCARD_ALL) 00321 goto skip; 00322 if (!(err = r3d_read_redv(s, pkt, &atom))) 00323 return 0; 00324 break; 00325 case MKTAG('R','E','D','A'): 00326 if (s->nb_streams < 2) 00327 return -1; 00328 if (s->streams[1]->discard == AVDISCARD_ALL) 00329 goto skip; 00330 if (!(err = r3d_read_reda(s, pkt, &atom))) 00331 return 0; 00332 break; 00333 default: 00334 skip: 00335 url_fskip(s->pb, atom.size-8); 00336 } 00337 } 00338 return err; 00339 } 00340 00341 static int r3d_probe(AVProbeData *p) 00342 { 00343 if (AV_RL32(p->buf + 4) == MKTAG('R','E','D','1')) 00344 return AVPROBE_SCORE_MAX; 00345 return 0; 00346 } 00347 00348 static int r3d_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags) 00349 { 00350 AVStream *st = s->streams[0]; // video stream 00351 R3DContext *r3d = s->priv_data; 00352 int frame_num; 00353 00354 if (!st->codec->time_base.num || !st->time_base.den) 00355 return -1; 00356 00357 frame_num = sample_time*st->codec->time_base.den/ 00358 ((int64_t)st->codec->time_base.num*st->time_base.den); 00359 dprintf(s, "seek frame num %d timestamp %lld\n", frame_num, sample_time); 00360 00361 if (frame_num < r3d->video_offsets_count) { 00362 url_fseek(s->pb, r3d->video_offsets_count, SEEK_SET); 00363 } else { 00364 av_log(s, AV_LOG_ERROR, "could not seek to frame %d\n", frame_num); 00365 return -1; 00366 } 00367 00368 return 0; 00369 } 00370 00371 static int r3d_close(AVFormatContext *s) 00372 { 00373 R3DContext *r3d = s->priv_data; 00374 00375 av_freep(&r3d->video_offsets); 00376 00377 return 0; 00378 } 00379 00380 AVInputFormat r3d_demuxer = { 00381 "r3d", 00382 NULL_IF_CONFIG_SMALL("REDCODE R3D format"), 00383 sizeof(R3DContext), 00384 r3d_probe, 00385 r3d_read_header, 00386 r3d_read_packet, 00387 r3d_close, 00388 r3d_seek, 00389 };