LCOV - code coverage report
Current view: top level - libavformat - r3d.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 147 232 63.4 %
Date: 2017-12-14 19:11:59 Functions: 8 11 72.7 %

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

Generated by: LCOV version 1.13