1/* 2 * R3D REDCODE demuxer 3 * Copyright (c) 2008 Baptiste Coudurier <baptiste dot coudurier at gmail dot com> 4 * 5 * This file is part of Libav. 6 * 7 * Libav 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 * Libav 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 Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22//#define DEBUG 23 24#include "libavutil/intreadwrite.h" 25#include "libavutil/dict.h" 26#include "libavutil/mathematics.h" 27#include "avformat.h" 28#include "internal.h" 29 30typedef struct { 31 unsigned video_offsets_count; 32 unsigned *video_offsets; 33 unsigned rdvo_offset; 34} R3DContext; 35 36typedef struct { 37 unsigned size; 38 uint32_t tag; 39 uint64_t offset; 40} Atom; 41 42static int read_atom(AVFormatContext *s, Atom *atom) 43{ 44 atom->offset = avio_tell(s->pb); 45 atom->size = avio_rb32(s->pb); 46 if (atom->size < 8) 47 return -1; 48 atom->tag = avio_rl32(s->pb); 49 av_dlog(s, "atom %u %.4s offset %#"PRIx64"\n", 50 atom->size, (char*)&atom->tag, atom->offset); 51 return atom->size; 52} 53 54static int r3d_read_red1(AVFormatContext *s) 55{ 56 AVStream *st = avformat_new_stream(s, NULL); 57 char filename[258]; 58 int tmp; 59 int av_unused tmp2; 60 61 if (!st) 62 return AVERROR(ENOMEM); 63 st->codec->codec_type = AVMEDIA_TYPE_VIDEO; 64 st->codec->codec_id = CODEC_ID_JPEG2000; 65 66 tmp = avio_r8(s->pb); // major version 67 tmp2 = avio_r8(s->pb); // minor version 68 av_dlog(s, "version %d.%d\n", tmp, tmp2); 69 70 tmp = avio_rb16(s->pb); // unknown 71 av_dlog(s, "unknown1 %d\n", tmp); 72 73 tmp = avio_rb32(s->pb); 74 avpriv_set_pts_info(st, 32, 1, tmp); 75 76 tmp = avio_rb32(s->pb); // filenum 77 av_dlog(s, "filenum %d\n", tmp); 78 79 avio_skip(s->pb, 32); // unknown 80 81 st->codec->width = avio_rb32(s->pb); 82 st->codec->height = avio_rb32(s->pb); 83 84 tmp = avio_rb16(s->pb); // unknown 85 av_dlog(s, "unknown2 %d\n", tmp); 86 87 st->codec->time_base.den = avio_rb16(s->pb); 88 st->codec->time_base.num = avio_rb16(s->pb); 89 90 tmp = avio_r8(s->pb); // audio channels 91 av_dlog(s, "audio channels %d\n", tmp); 92 if (tmp > 0) { 93 AVStream *ast = avformat_new_stream(s, NULL); 94 if (!ast) 95 return AVERROR(ENOMEM); 96 ast->codec->codec_type = AVMEDIA_TYPE_AUDIO; 97 ast->codec->codec_id = CODEC_ID_PCM_S32BE; 98 ast->codec->channels = tmp; 99 avpriv_set_pts_info(ast, 32, 1, st->time_base.den); 100 } 101 102 avio_read(s->pb, filename, 257); 103 filename[sizeof(filename)-1] = 0; 104 av_dict_set(&st->metadata, "filename", filename, 0); 105 106 av_dlog(s, "filename %s\n", filename); 107 av_dlog(s, "resolution %dx%d\n", st->codec->width, st->codec->height); 108 av_dlog(s, "timescale %d\n", st->time_base.den); 109 av_dlog(s, "frame rate %d/%d\n", 110 st->codec->time_base.num, st->codec->time_base.den); 111 112 return 0; 113} 114 115static int r3d_read_rdvo(AVFormatContext *s, Atom *atom) 116{ 117 R3DContext *r3d = s->priv_data; 118 AVStream *st = s->streams[0]; 119 int i; 120 121 r3d->video_offsets_count = (atom->size - 8) / 4; 122 r3d->video_offsets = av_malloc(atom->size); 123 if (!r3d->video_offsets) 124 return AVERROR(ENOMEM); 125 126 for (i = 0; i < r3d->video_offsets_count; i++) { 127 r3d->video_offsets[i] = avio_rb32(s->pb); 128 if (!r3d->video_offsets[i]) { 129 r3d->video_offsets_count = i; 130 break; 131 } 132 av_dlog(s, "video offset %d: %#x\n", i, r3d->video_offsets[i]); 133 } 134 135 if (st->codec->time_base.den) 136 st->duration = (uint64_t)r3d->video_offsets_count* 137 st->time_base.den*st->codec->time_base.num/st->codec->time_base.den; 138 av_dlog(s, "duration %"PRId64"\n", st->duration); 139 140 return 0; 141} 142 143static void r3d_read_reos(AVFormatContext *s) 144{ 145 R3DContext *r3d = s->priv_data; 146 int av_unused tmp; 147 148 r3d->rdvo_offset = avio_rb32(s->pb); 149 avio_rb32(s->pb); // rdvs offset 150 avio_rb32(s->pb); // rdao offset 151 avio_rb32(s->pb); // rdas offset 152 153 tmp = avio_rb32(s->pb); 154 av_dlog(s, "num video chunks %d\n", tmp); 155 156 tmp = avio_rb32(s->pb); 157 av_dlog(s, "num audio chunks %d\n", tmp); 158 159 avio_skip(s->pb, 6*4); 160} 161 162static int r3d_read_header(AVFormatContext *s, AVFormatParameters *ap) 163{ 164 R3DContext *r3d = s->priv_data; 165 Atom atom; 166 int ret; 167 168 if (read_atom(s, &atom) < 0) { 169 av_log(s, AV_LOG_ERROR, "error reading atom\n"); 170 return -1; 171 } 172 if (atom.tag == MKTAG('R','E','D','1')) { 173 if ((ret = r3d_read_red1(s)) < 0) { 174 av_log(s, AV_LOG_ERROR, "error parsing 'red1' atom\n"); 175 return ret; 176 } 177 } else { 178 av_log(s, AV_LOG_ERROR, "could not find 'red1' atom\n"); 179 return -1; 180 } 181 182 s->data_offset = avio_tell(s->pb); 183 av_dlog(s, "data offset %#"PRIx64"\n", s->data_offset); 184 if (!s->pb->seekable) 185 return 0; 186 // find REOB/REOF/REOS to load index 187 avio_seek(s->pb, avio_size(s->pb)-48-8, SEEK_SET); 188 if (read_atom(s, &atom) < 0) 189 av_log(s, AV_LOG_ERROR, "error reading end atom\n"); 190 191 if (atom.tag != MKTAG('R','E','O','B') && 192 atom.tag != MKTAG('R','E','O','F') && 193 atom.tag != MKTAG('R','E','O','S')) 194 goto out; 195 196 r3d_read_reos(s); 197 198 if (r3d->rdvo_offset) { 199 avio_seek(s->pb, r3d->rdvo_offset, SEEK_SET); 200 if (read_atom(s, &atom) < 0) 201 av_log(s, AV_LOG_ERROR, "error reading 'rdvo' atom\n"); 202 if (atom.tag == MKTAG('R','D','V','O')) { 203 if (r3d_read_rdvo(s, &atom) < 0) 204 av_log(s, AV_LOG_ERROR, "error parsing 'rdvo' atom\n"); 205 } 206 } 207 208 out: 209 avio_seek(s->pb, s->data_offset, SEEK_SET); 210 return 0; 211} 212 213static int r3d_read_redv(AVFormatContext *s, AVPacket *pkt, Atom *atom) 214{ 215 AVStream *st = s->streams[0]; 216 int tmp; 217 int av_unused tmp2; 218 uint64_t pos = avio_tell(s->pb); 219 unsigned dts; 220 int ret; 221 222 dts = avio_rb32(s->pb); 223 224 tmp = avio_rb32(s->pb); 225 av_dlog(s, "frame num %d\n", tmp); 226 227 tmp = avio_r8(s->pb); // major version 228 tmp2 = avio_r8(s->pb); // minor version 229 av_dlog(s, "version %d.%d\n", tmp, tmp2); 230 231 tmp = avio_rb16(s->pb); // unknown 232 av_dlog(s, "unknown %d\n", tmp); 233 234 if (tmp > 4) { 235 tmp = avio_rb16(s->pb); // unknown 236 av_dlog(s, "unknown %d\n", tmp); 237 238 tmp = avio_rb16(s->pb); // unknown 239 av_dlog(s, "unknown %d\n", tmp); 240 241 tmp = avio_rb32(s->pb); 242 av_dlog(s, "width %d\n", tmp); 243 tmp = avio_rb32(s->pb); 244 av_dlog(s, "height %d\n", tmp); 245 246 tmp = avio_rb32(s->pb); 247 av_dlog(s, "metadata len %d\n", tmp); 248 } 249 tmp = atom->size - 8 - (avio_tell(s->pb) - pos); 250 if (tmp < 0) 251 return -1; 252 ret = av_get_packet(s->pb, pkt, tmp); 253 if (ret < 0) { 254 av_log(s, AV_LOG_ERROR, "error reading video packet\n"); 255 return -1; 256 } 257 258 pkt->stream_index = 0; 259 pkt->dts = dts; 260 if (st->codec->time_base.den) 261 pkt->duration = (uint64_t)st->time_base.den* 262 st->codec->time_base.num/st->codec->time_base.den; 263 av_dlog(s, "pkt dts %"PRId64" duration %d\n", pkt->dts, pkt->duration); 264 265 return 0; 266} 267 268static int r3d_read_reda(AVFormatContext *s, AVPacket *pkt, Atom *atom) 269{ 270 AVStream *st = s->streams[1]; 271 int av_unused tmp, tmp2; 272 int samples, size; 273 uint64_t pos = avio_tell(s->pb); 274 unsigned dts; 275 int ret; 276 277 dts = avio_rb32(s->pb); 278 279 st->codec->sample_rate = avio_rb32(s->pb); 280 281 samples = avio_rb32(s->pb); 282 283 tmp = avio_rb32(s->pb); 284 av_dlog(s, "packet num %d\n", tmp); 285 286 tmp = avio_rb16(s->pb); // unkown 287 av_dlog(s, "unknown %d\n", tmp); 288 289 tmp = avio_r8(s->pb); // major version 290 tmp2 = avio_r8(s->pb); // minor version 291 av_dlog(s, "version %d.%d\n", tmp, tmp2); 292 293 tmp = avio_rb32(s->pb); // unknown 294 av_dlog(s, "unknown %d\n", tmp); 295 296 size = atom->size - 8 - (avio_tell(s->pb) - pos); 297 if (size < 0) 298 return -1; 299 ret = av_get_packet(s->pb, pkt, size); 300 if (ret < 0) { 301 av_log(s, AV_LOG_ERROR, "error reading audio packet\n"); 302 return ret; 303 } 304 305 pkt->stream_index = 1; 306 pkt->dts = dts; 307 pkt->duration = av_rescale(samples, st->time_base.den, st->codec->sample_rate); 308 av_dlog(s, "pkt dts %"PRId64" duration %d samples %d sample rate %d\n", 309 pkt->dts, pkt->duration, samples, st->codec->sample_rate); 310 311 return 0; 312} 313 314static int r3d_read_packet(AVFormatContext *s, AVPacket *pkt) 315{ 316 Atom atom; 317 int err = 0; 318 319 while (!err) { 320 if (read_atom(s, &atom) < 0) { 321 err = -1; 322 break; 323 } 324 switch (atom.tag) { 325 case MKTAG('R','E','D','V'): 326 if (s->streams[0]->discard == AVDISCARD_ALL) 327 goto skip; 328 if (!(err = r3d_read_redv(s, pkt, &atom))) 329 return 0; 330 break; 331 case MKTAG('R','E','D','A'): 332 if (s->nb_streams < 2) 333 return -1; 334 if (s->streams[1]->discard == AVDISCARD_ALL) 335 goto skip; 336 if (!(err = r3d_read_reda(s, pkt, &atom))) 337 return 0; 338 break; 339 default: 340 skip: 341 avio_skip(s->pb, atom.size-8); 342 } 343 } 344 return err; 345} 346 347static int r3d_probe(AVProbeData *p) 348{ 349 if (AV_RL32(p->buf + 4) == MKTAG('R','E','D','1')) 350 return AVPROBE_SCORE_MAX; 351 return 0; 352} 353 354static int r3d_seek(AVFormatContext *s, int stream_index, int64_t sample_time, int flags) 355{ 356 AVStream *st = s->streams[0]; // video stream 357 R3DContext *r3d = s->priv_data; 358 int frame_num; 359 360 if (!st->codec->time_base.num || !st->time_base.den) 361 return -1; 362 363 frame_num = sample_time*st->codec->time_base.den/ 364 ((int64_t)st->codec->time_base.num*st->time_base.den); 365 av_dlog(s, "seek frame num %d timestamp %"PRId64"\n", 366 frame_num, sample_time); 367 368 if (frame_num < r3d->video_offsets_count) { 369 avio_seek(s->pb, r3d->video_offsets_count, SEEK_SET); 370 } else { 371 av_log(s, AV_LOG_ERROR, "could not seek to frame %d\n", frame_num); 372 return -1; 373 } 374 375 return 0; 376} 377 378static int r3d_close(AVFormatContext *s) 379{ 380 R3DContext *r3d = s->priv_data; 381 382 av_freep(&r3d->video_offsets); 383 384 return 0; 385} 386 387AVInputFormat ff_r3d_demuxer = { 388 .name = "r3d", 389 .long_name = NULL_IF_CONFIG_SMALL("REDCODE R3D format"), 390 .priv_data_size = sizeof(R3DContext), 391 .read_probe = r3d_probe, 392 .read_header = r3d_read_header, 393 .read_packet = r3d_read_packet, 394 .read_close = r3d_close, 395 .read_seek = r3d_seek, 396}; 397