LCOV - code coverage report
Current view: top level - libavformat - mvdec.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 187 296 63.2 %
Date: 2017-12-17 16:07:53 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /*
       2             :  * Silicon Graphics Movie demuxer
       3             :  * Copyright (c) 2012 Peter Ross
       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             : /**
      23             :  * @file
      24             :  * Silicon Graphics Movie demuxer
      25             :  */
      26             : 
      27             : #include "libavutil/channel_layout.h"
      28             : #include "libavutil/eval.h"
      29             : #include "libavutil/intreadwrite.h"
      30             : #include "libavutil/rational.h"
      31             : 
      32             : #include "avformat.h"
      33             : #include "internal.h"
      34             : 
      35             : typedef struct MvContext {
      36             :     int nb_video_tracks;
      37             :     int nb_audio_tracks;
      38             : 
      39             :     int eof_count;        ///< number of streams that have finished
      40             :     int stream_index;     ///< current stream index
      41             :     int frame[2];         ///< frame nb for current stream
      42             : 
      43             :     int acompression;     ///< compression level for audio stream
      44             :     int aformat;          ///< audio format
      45             : } MvContext;
      46             : 
      47             : #define AUDIO_FORMAT_SIGNED 401
      48             : 
      49        6130 : static int mv_probe(AVProbeData *p)
      50             : {
      51        6133 :     if (AV_RB32(p->buf) == MKBETAG('M', 'O', 'V', 'I') &&
      52           3 :         AV_RB16(p->buf + 4) < 3)
      53           3 :         return AVPROBE_SCORE_MAX;
      54        6127 :     return 0;
      55             : }
      56             : 
      57          42 : static char *var_read_string(AVIOContext *pb, int size)
      58             : {
      59             :     int n;
      60             :     char *str;
      61             : 
      62          42 :     if (size < 0 || size == INT_MAX)
      63           0 :         return NULL;
      64             : 
      65          42 :     str = av_malloc(size + 1);
      66          42 :     if (!str)
      67           0 :         return NULL;
      68          42 :     n = avio_get_str(pb, size, str, size + 1);
      69          42 :     if (n < size)
      70           0 :         avio_skip(pb, size - n);
      71          42 :     return str;
      72             : }
      73             : 
      74          30 : static int var_read_int(AVIOContext *pb, int size)
      75             : {
      76             :     int v;
      77          30 :     char *s = var_read_string(pb, size);
      78          30 :     if (!s)
      79           0 :         return 0;
      80          30 :     v = strtol(s, NULL, 10);
      81          30 :     av_free(s);
      82          30 :     return v;
      83             : }
      84             : 
      85           5 : static AVRational var_read_float(AVIOContext *pb, int size)
      86             : {
      87             :     AVRational v;
      88           5 :     char *s = var_read_string(pb, size);
      89           5 :     if (!s)
      90           0 :         return (AVRational) { 0, 0 };
      91           5 :     v = av_d2q(av_strtod(s, NULL), INT_MAX);
      92           5 :     av_free(s);
      93           5 :     return v;
      94             : }
      95             : 
      96           4 : static void var_read_metadata(AVFormatContext *avctx, const char *tag, int size)
      97             : {
      98           4 :     char *value = var_read_string(avctx->pb, size);
      99           4 :     if (value)
     100           4 :         av_dict_set(&avctx->metadata, tag, value, AV_DICT_DONT_STRDUP_VAL);
     101           4 : }
     102             : 
     103           2 : static int set_channels(AVFormatContext *avctx, AVStream *st, int channels)
     104             : {
     105           2 :     if (channels <= 0) {
     106           0 :         av_log(avctx, AV_LOG_ERROR, "Channel count %d invalid.\n", channels);
     107           0 :         return AVERROR_INVALIDDATA;
     108             :     }
     109           2 :     st->codecpar->channels       = channels;
     110           4 :     st->codecpar->channel_layout = (st->codecpar->channels == 1) ? AV_CH_LAYOUT_MONO
     111           2 :                                                                  : AV_CH_LAYOUT_STEREO;
     112           2 :     return 0;
     113             : }
     114             : 
     115             : /**
     116             :  * Parse global variable
     117             :  * @return < 0 if unknown
     118             :  */
     119          15 : static int parse_global_var(AVFormatContext *avctx, AVStream *st,
     120             :                             const char *name, int size)
     121             : {
     122          15 :     MvContext *mv = avctx->priv_data;
     123          15 :     AVIOContext *pb = avctx->pb;
     124          15 :     if (!strcmp(name, "__NUM_I_TRACKS")) {
     125           3 :         mv->nb_video_tracks = var_read_int(pb, size);
     126          12 :     } else if (!strcmp(name, "__NUM_A_TRACKS")) {
     127           3 :         mv->nb_audio_tracks = var_read_int(pb, size);
     128           9 :     } else if (!strcmp(name, "COMMENT") || !strcmp(name, "TITLE")) {
     129           0 :         var_read_metadata(avctx, name, size);
     130          12 :     } else if (!strcmp(name, "LOOP_MODE") || !strcmp(name, "NUM_LOOPS") ||
     131           3 :                !strcmp(name, "OPTIMIZED")) {
     132           9 :         avio_skip(pb, size); // ignore
     133             :     } else
     134           0 :         return AVERROR_INVALIDDATA;
     135             : 
     136          15 :     return 0;
     137             : }
     138             : 
     139             : /**
     140             :  * Parse audio variable
     141             :  * @return < 0 if unknown
     142             :  */
     143          12 : static int parse_audio_var(AVFormatContext *avctx, AVStream *st,
     144             :                            const char *name, int size)
     145             : {
     146          12 :     MvContext *mv = avctx->priv_data;
     147          12 :     AVIOContext *pb = avctx->pb;
     148          12 :     if (!strcmp(name, "__DIR_COUNT")) {
     149           2 :         st->nb_frames = var_read_int(pb, size);
     150          10 :     } else if (!strcmp(name, "AUDIO_FORMAT")) {
     151           2 :         mv->aformat = var_read_int(pb, size);
     152           8 :     } else if (!strcmp(name, "COMPRESSION")) {
     153           2 :         mv->acompression = var_read_int(pb, size);
     154           6 :     } else if (!strcmp(name, "DEFAULT_VOL")) {
     155           0 :         var_read_metadata(avctx, name, size);
     156           6 :     } else if (!strcmp(name, "NUM_CHANNELS")) {
     157           2 :         return set_channels(avctx, st, var_read_int(pb, size));
     158           4 :     } else if (!strcmp(name, "SAMPLE_RATE")) {
     159           2 :         st->codecpar->sample_rate = var_read_int(pb, size);
     160           2 :         avpriv_set_pts_info(st, 33, 1, st->codecpar->sample_rate);
     161           2 :     } else if (!strcmp(name, "SAMPLE_WIDTH")) {
     162           2 :         st->codecpar->bits_per_coded_sample = var_read_int(pb, size) * 8;
     163             :     } else
     164           0 :         return AVERROR_INVALIDDATA;
     165             : 
     166          10 :     return 0;
     167             : }
     168             : 
     169             : /**
     170             :  * Parse video variable
     171             :  * @return < 0 if unknown
     172             :  */
     173          30 : static int parse_video_var(AVFormatContext *avctx, AVStream *st,
     174             :                            const char *name, int size)
     175             : {
     176          30 :     AVIOContext *pb = avctx->pb;
     177          30 :     if (!strcmp(name, "__DIR_COUNT")) {
     178           3 :         st->nb_frames = st->duration = var_read_int(pb, size);
     179          27 :     } else if (!strcmp(name, "COMPRESSION")) {
     180           3 :         char *str = var_read_string(pb, size);
     181           3 :         if (!str)
     182           0 :             return AVERROR_INVALIDDATA;
     183           3 :         if (!strcmp(str, "1")) {
     184           1 :             st->codecpar->codec_id = AV_CODEC_ID_MVC1;
     185           2 :         } else if (!strcmp(str, "2")) {
     186           0 :             st->codecpar->format = AV_PIX_FMT_ABGR;
     187           0 :             st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
     188           2 :         } else if (!strcmp(str, "3")) {
     189           1 :             st->codecpar->codec_id = AV_CODEC_ID_SGIRLE;
     190           1 :         } else if (!strcmp(str, "10")) {
     191           0 :             st->codecpar->codec_id = AV_CODEC_ID_MJPEG;
     192           1 :         } else if (!strcmp(str, "MVC2")) {
     193           1 :             st->codecpar->codec_id = AV_CODEC_ID_MVC2;
     194             :         } else {
     195           0 :             avpriv_request_sample(avctx, "Video compression %s", str);
     196             :         }
     197           3 :         av_free(str);
     198          24 :     } else if (!strcmp(name, "FPS")) {
     199           3 :         AVRational fps = var_read_float(pb, size);
     200           3 :         avpriv_set_pts_info(st, 64, fps.den, fps.num);
     201           3 :         st->avg_frame_rate = fps;
     202          21 :     } else if (!strcmp(name, "HEIGHT")) {
     203           3 :         st->codecpar->height = var_read_int(pb, size);
     204          18 :     } else if (!strcmp(name, "PIXEL_ASPECT")) {
     205           2 :         st->sample_aspect_ratio = var_read_float(pb, size);
     206           4 :         av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den,
     207           4 :                   st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
     208             :                   INT_MAX);
     209          16 :     } else if (!strcmp(name, "WIDTH")) {
     210           3 :         st->codecpar->width = var_read_int(pb, size);
     211          13 :     } else if (!strcmp(name, "ORIENTATION")) {
     212           3 :         if (var_read_int(pb, size) == 1101) {
     213           2 :             st->codecpar->extradata      = av_strdup("BottomUp");
     214           2 :             st->codecpar->extradata_size = 9;
     215             :         }
     216          10 :     } else if (!strcmp(name, "Q_SPATIAL") || !strcmp(name, "Q_TEMPORAL")) {
     217           4 :         var_read_metadata(avctx, name, size);
     218           6 :     } else if (!strcmp(name, "INTERLACING") || !strcmp(name, "PACKING")) {
     219           6 :         avio_skip(pb, size); // ignore
     220             :     } else
     221           0 :         return AVERROR_INVALIDDATA;
     222             : 
     223          30 :     return 0;
     224             : }
     225             : 
     226           8 : static int read_table(AVFormatContext *avctx, AVStream *st,
     227             :                        int (*parse)(AVFormatContext *avctx, AVStream *st,
     228             :                                     const char *name, int size))
     229             : {
     230             :     unsigned count;
     231             :     int i;
     232             : 
     233           8 :     AVIOContext *pb = avctx->pb;
     234           8 :     avio_skip(pb, 4);
     235           8 :     count = avio_rb32(pb);
     236           8 :     avio_skip(pb, 4);
     237         130 :     for (i = 0; i < count; i++) {
     238             :         char name[17];
     239             :         int size;
     240             : 
     241          57 :         if (avio_feof(pb))
     242           0 :             return AVERROR_EOF;
     243             : 
     244          57 :         avio_read(pb, name, 16);
     245          57 :         name[sizeof(name) - 1] = 0;
     246          57 :         size = avio_rb32(pb);
     247          57 :         if (size < 0) {
     248           0 :             av_log(avctx, AV_LOG_ERROR, "entry size %d is invalid\n", size);
     249           0 :             return AVERROR_INVALIDDATA;
     250             :         }
     251          57 :         if (parse(avctx, st, name, size) < 0) {
     252           0 :             avpriv_request_sample(avctx, "Variable %s", name);
     253           0 :             avio_skip(pb, size);
     254             :         }
     255             :     }
     256           8 :     return 0;
     257             : }
     258             : 
     259           5 : static void read_index(AVIOContext *pb, AVStream *st)
     260             : {
     261           5 :     uint64_t timestamp = 0;
     262             :     int i;
     263         732 :     for (i = 0; i < st->nb_frames; i++) {
     264         727 :         uint32_t pos  = avio_rb32(pb);
     265         727 :         uint32_t size = avio_rb32(pb);
     266         727 :         avio_skip(pb, 8);
     267         727 :         av_add_index_entry(st, pos, timestamp, size, 0, AVINDEX_KEYFRAME);
     268         727 :         if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
     269         391 :             timestamp += size / (st->codecpar->channels * 2);
     270             :         } else {
     271         336 :             timestamp++;
     272             :         }
     273             :     }
     274           5 : }
     275             : 
     276           3 : static int mv_read_header(AVFormatContext *avctx)
     277             : {
     278           3 :     MvContext *mv = avctx->priv_data;
     279           3 :     AVIOContext *pb = avctx->pb;
     280           3 :     AVStream *ast = NULL, *vst = NULL; //initialization to suppress warning
     281             :     int version, i;
     282             :     int ret;
     283             : 
     284           3 :     avio_skip(pb, 4);
     285             : 
     286           3 :     version = avio_rb16(pb);
     287           3 :     if (version == 2) {
     288             :         uint64_t timestamp;
     289             :         int v;
     290           0 :         avio_skip(pb, 22);
     291             : 
     292             :         /* allocate audio track first to prevent unnecessary seeking
     293             :          * (audio packet always precede video packet for a given frame) */
     294           0 :         ast = avformat_new_stream(avctx, NULL);
     295           0 :         if (!ast)
     296           0 :             return AVERROR(ENOMEM);
     297             : 
     298           0 :         vst = avformat_new_stream(avctx, NULL);
     299           0 :         if (!vst)
     300           0 :             return AVERROR(ENOMEM);
     301           0 :         avpriv_set_pts_info(vst, 64, 1, 15);
     302           0 :         vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     303           0 :         vst->avg_frame_rate    = av_inv_q(vst->time_base);
     304           0 :         vst->nb_frames         = avio_rb32(pb);
     305           0 :         v = avio_rb32(pb);
     306           0 :         switch (v) {
     307           0 :         case 1:
     308           0 :             vst->codecpar->codec_id = AV_CODEC_ID_MVC1;
     309           0 :             break;
     310           0 :         case 2:
     311           0 :             vst->codecpar->format = AV_PIX_FMT_ARGB;
     312           0 :             vst->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
     313           0 :             break;
     314           0 :         default:
     315           0 :             avpriv_request_sample(avctx, "Video compression %i", v);
     316           0 :             break;
     317             :         }
     318           0 :         vst->codecpar->codec_tag = 0;
     319           0 :         vst->codecpar->width     = avio_rb32(pb);
     320           0 :         vst->codecpar->height    = avio_rb32(pb);
     321           0 :         avio_skip(pb, 12);
     322             : 
     323           0 :         ast->codecpar->codec_type  = AVMEDIA_TYPE_AUDIO;
     324           0 :         ast->nb_frames          = vst->nb_frames;
     325           0 :         ast->codecpar->sample_rate = avio_rb32(pb);
     326           0 :         if (ast->codecpar->sample_rate <= 0) {
     327           0 :             av_log(avctx, AV_LOG_ERROR, "Invalid sample rate %d\n", ast->codecpar->sample_rate);
     328           0 :             return AVERROR_INVALIDDATA;
     329             :         }
     330           0 :         avpriv_set_pts_info(ast, 33, 1, ast->codecpar->sample_rate);
     331           0 :         if (set_channels(avctx, ast, avio_rb32(pb)) < 0)
     332           0 :             return AVERROR_INVALIDDATA;
     333             : 
     334           0 :         v = avio_rb32(pb);
     335           0 :         if (v == AUDIO_FORMAT_SIGNED) {
     336           0 :             ast->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE;
     337             :         } else {
     338           0 :             avpriv_request_sample(avctx, "Audio compression (format %i)", v);
     339             :         }
     340             : 
     341           0 :         avio_skip(pb, 12);
     342           0 :         var_read_metadata(avctx, "title", 0x80);
     343           0 :         var_read_metadata(avctx, "comment", 0x100);
     344           0 :         avio_skip(pb, 0x80);
     345             : 
     346           0 :         timestamp = 0;
     347           0 :         for (i = 0; i < vst->nb_frames; i++) {
     348           0 :             uint32_t pos   = avio_rb32(pb);
     349           0 :             uint32_t asize = avio_rb32(pb);
     350           0 :             uint32_t vsize = avio_rb32(pb);
     351           0 :             if (avio_feof(pb))
     352           0 :                 return AVERROR_INVALIDDATA;
     353           0 :             avio_skip(pb, 8);
     354           0 :             av_add_index_entry(ast, pos, timestamp, asize, 0, AVINDEX_KEYFRAME);
     355           0 :             av_add_index_entry(vst, pos + asize, i, vsize, 0, AVINDEX_KEYFRAME);
     356           0 :             timestamp += asize / (ast->codecpar->channels * 2);
     357             :         }
     358           3 :     } else if (!version && avio_rb16(pb) == 3) {
     359           3 :         avio_skip(pb, 4);
     360             : 
     361           3 :         if ((ret = read_table(avctx, NULL, parse_global_var)) < 0)
     362           0 :             return ret;
     363             : 
     364           3 :         if (mv->nb_audio_tracks > 1) {
     365           0 :             avpriv_request_sample(avctx, "Multiple audio streams support");
     366           0 :             return AVERROR_PATCHWELCOME;
     367           3 :         } else if (mv->nb_audio_tracks) {
     368           2 :             ast = avformat_new_stream(avctx, NULL);
     369           2 :             if (!ast)
     370           0 :                 return AVERROR(ENOMEM);
     371           2 :             ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
     372           2 :             if ((read_table(avctx, ast, parse_audio_var)) < 0)
     373           0 :                 return ret;
     374           4 :             if (mv->acompression == 100 &&
     375           4 :                 mv->aformat == AUDIO_FORMAT_SIGNED &&
     376           2 :                 ast->codecpar->bits_per_coded_sample == 16) {
     377           2 :                 ast->codecpar->codec_id = AV_CODEC_ID_PCM_S16BE;
     378             :             } else {
     379           0 :                 avpriv_request_sample(avctx,
     380             :                                       "Audio compression %i (format %i, sr %i)",
     381             :                                       mv->acompression, mv->aformat,
     382           0 :                                       ast->codecpar->bits_per_coded_sample);
     383           0 :                 ast->codecpar->codec_id = AV_CODEC_ID_NONE;
     384             :             }
     385           2 :             if (ast->codecpar->channels <= 0) {
     386           0 :                 av_log(avctx, AV_LOG_ERROR, "No valid channel count found.\n");
     387           0 :                 return AVERROR_INVALIDDATA;
     388             :             }
     389             :         }
     390             : 
     391           3 :         if (mv->nb_video_tracks > 1) {
     392           0 :             avpriv_request_sample(avctx, "Multiple video streams support");
     393           0 :             return AVERROR_PATCHWELCOME;
     394           3 :         } else if (mv->nb_video_tracks) {
     395           3 :             vst = avformat_new_stream(avctx, NULL);
     396           3 :             if (!vst)
     397           0 :                 return AVERROR(ENOMEM);
     398           3 :             vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
     399           3 :             if ((ret = read_table(avctx, vst, parse_video_var))<0)
     400           0 :                 return ret;
     401             :         }
     402             : 
     403           3 :         if (mv->nb_audio_tracks)
     404           2 :             read_index(pb, ast);
     405             : 
     406           6 :         if (mv->nb_video_tracks)
     407           3 :             read_index(pb, vst);
     408             :     } else {
     409           0 :         avpriv_request_sample(avctx, "Version %i", version);
     410           0 :         return AVERROR_PATCHWELCOME;
     411             :     }
     412             : 
     413           3 :     return 0;
     414             : }
     415             : 
     416         150 : static int mv_read_packet(AVFormatContext *avctx, AVPacket *pkt)
     417             : {
     418         150 :     MvContext *mv = avctx->priv_data;
     419         150 :     AVIOContext *pb = avctx->pb;
     420         150 :     AVStream *st = avctx->streams[mv->stream_index];
     421             :     const AVIndexEntry *index;
     422         150 :     int frame = mv->frame[mv->stream_index];
     423             :     int64_t ret;
     424             :     uint64_t pos;
     425             : 
     426         150 :     if (frame < st->nb_index_entries) {
     427         148 :         index = &st->index_entries[frame];
     428         148 :         pos   = avio_tell(pb);
     429         148 :         if (index->pos > pos)
     430          76 :             avio_skip(pb, index->pos - pos);
     431          72 :         else if (index->pos < pos) {
     432          61 :             if (!(pb->seekable & AVIO_SEEKABLE_NORMAL))
     433           0 :                 return AVERROR(EIO);
     434          61 :             ret = avio_seek(pb, index->pos, SEEK_SET);
     435          61 :             if (ret < 0)
     436           0 :                 return ret;
     437             :         }
     438         148 :         ret = av_get_packet(pb, pkt, index->size);
     439         148 :         if (ret < 0)
     440           0 :             return ret;
     441             : 
     442         148 :         pkt->stream_index = mv->stream_index;
     443         148 :         pkt->pts          = index->timestamp;
     444         148 :         pkt->flags       |= AV_PKT_FLAG_KEY;
     445             : 
     446         148 :         mv->frame[mv->stream_index]++;
     447         148 :         mv->eof_count = 0;
     448             :     } else {
     449           2 :         mv->eof_count++;
     450           2 :         if (mv->eof_count >= avctx->nb_streams)
     451           1 :             return AVERROR_EOF;
     452             : 
     453             :         // avoid returning 0 without a packet
     454           1 :         return AVERROR(EAGAIN);
     455             :     }
     456             : 
     457         148 :     mv->stream_index++;
     458         148 :     if (mv->stream_index >= avctx->nb_streams)
     459          86 :         mv->stream_index = 0;
     460             : 
     461         148 :     return 0;
     462             : }
     463             : 
     464           0 : static int mv_read_seek(AVFormatContext *avctx, int stream_index,
     465             :                         int64_t timestamp, int flags)
     466             : {
     467           0 :     MvContext *mv = avctx->priv_data;
     468           0 :     AVStream *st = avctx->streams[stream_index];
     469             :     int frame, i;
     470             : 
     471           0 :     if ((flags & AVSEEK_FLAG_FRAME) || (flags & AVSEEK_FLAG_BYTE))
     472           0 :         return AVERROR(ENOSYS);
     473             : 
     474           0 :     if (!(avctx->pb->seekable & AVIO_SEEKABLE_NORMAL))
     475           0 :         return AVERROR(EIO);
     476             : 
     477           0 :     frame = av_index_search_timestamp(st, timestamp, flags);
     478           0 :     if (frame < 0)
     479           0 :         return AVERROR_INVALIDDATA;
     480             : 
     481           0 :     for (i = 0; i < avctx->nb_streams; i++)
     482           0 :         mv->frame[i] = frame;
     483           0 :     return 0;
     484             : }
     485             : 
     486             : AVInputFormat ff_mv_demuxer = {
     487             :     .name           = "mv",
     488             :     .long_name      = NULL_IF_CONFIG_SMALL("Silicon Graphics Movie"),
     489             :     .priv_data_size = sizeof(MvContext),
     490             :     .read_probe     = mv_probe,
     491             :     .read_header    = mv_read_header,
     492             :     .read_packet    = mv_read_packet,
     493             :     .read_seek      = mv_read_seek,
     494             : };

Generated by: LCOV version 1.13