/src/ffmpeg/libavformat/dxa.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* | 
| 2 |  |  * DXA demuxer | 
| 3 |  |  * Copyright (c) 2007 Konstantin Shishkov | 
| 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 <inttypes.h> | 
| 23 |  |  | 
| 24 |  | #include "libavutil/intreadwrite.h" | 
| 25 |  | #include "avformat.h" | 
| 26 |  | #include "demux.h" | 
| 27 |  | #include "internal.h" | 
| 28 |  | #include "riff.h" | 
| 29 |  |  | 
| 30 | 4.85k | #define DXA_EXTRA_SIZE  9 | 
| 31 |  |  | 
| 32 |  | typedef struct DXAContext { | 
| 33 |  |     int frames; | 
| 34 |  |     int has_sound; | 
| 35 |  |     int bpc; | 
| 36 |  |     uint32_t bytes_left; | 
| 37 |  |     int64_t wavpos, vidpos; | 
| 38 |  |     int readvid; | 
| 39 |  | }DXAContext; | 
| 40 |  |  | 
| 41 |  | static int dxa_probe(const AVProbeData *p) | 
| 42 | 358k | { | 
| 43 | 358k |     int w, h; | 
| 44 | 358k |     if (p->buf_size < 15) | 
| 45 | 53.7k |         return 0; | 
| 46 | 304k |     w = AV_RB16(p->buf + 11); | 
| 47 | 304k |     h = AV_RB16(p->buf + 13); | 
| 48 |  |     /* check file header */ | 
| 49 | 304k |     if (p->buf[0] == 'D' && p->buf[1] == 'E' && | 
| 50 | 304k |         p->buf[2] == 'X' && p->buf[3] == 'A' && | 
| 51 | 304k |         w && w <= 2048 && h && h <= 2048) | 
| 52 | 74 |         return AVPROBE_SCORE_MAX; | 
| 53 | 304k |     else | 
| 54 | 304k |         return 0; | 
| 55 | 304k | } | 
| 56 |  |  | 
| 57 |  | static int dxa_read_header(AVFormatContext *s) | 
| 58 | 7.28k | { | 
| 59 | 7.28k |     AVIOContext *pb = s->pb; | 
| 60 | 7.28k |     DXAContext *c = s->priv_data; | 
| 61 | 7.28k |     AVStream *st, *ast; | 
| 62 | 7.28k |     uint32_t tag; | 
| 63 | 7.28k |     int32_t fps; | 
| 64 | 7.28k |     int w, h; | 
| 65 | 7.28k |     int num, den; | 
| 66 | 7.28k |     int flags; | 
| 67 | 7.28k |     int ret; | 
| 68 |  |  | 
| 69 | 7.28k |     tag = avio_rl32(pb); | 
| 70 | 7.28k |     if (tag != MKTAG('D', 'E', 'X', 'A')) | 
| 71 | 4.16k |         return AVERROR_INVALIDDATA; | 
| 72 | 3.12k |     flags = avio_r8(pb); | 
| 73 | 3.12k |     c->frames = avio_rb16(pb); | 
| 74 | 3.12k |     if(!c->frames){ | 
| 75 | 3 |         av_log(s, AV_LOG_ERROR, "File contains no frames ???\n"); | 
| 76 | 3 |         return AVERROR_INVALIDDATA; | 
| 77 | 3 |     } | 
| 78 |  |  | 
| 79 | 3.11k |     fps = avio_rb32(pb); | 
| 80 | 3.11k |     if(fps > 0){ | 
| 81 | 1.84k |         den = 1000; | 
| 82 | 1.84k |         num = fps; | 
| 83 | 1.84k |     }else if (fps < 0 && fps > INT_MIN){ | 
| 84 | 978 |         den = 100000; | 
| 85 | 978 |         num = -fps; | 
| 86 | 978 |     }else{ | 
| 87 | 295 |         den = 10; | 
| 88 | 295 |         num = 1; | 
| 89 | 295 |     } | 
| 90 | 3.11k |     w = avio_rb16(pb); | 
| 91 | 3.11k |     h = avio_rb16(pb); | 
| 92 | 3.11k |     c->has_sound = 0; | 
| 93 |  |  | 
| 94 | 3.11k |     st = avformat_new_stream(s, NULL); | 
| 95 | 3.11k |     if (!st) | 
| 96 | 0 |         return AVERROR(ENOMEM); | 
| 97 |  |  | 
| 98 |  |     // Parse WAV data header | 
| 99 | 3.11k |     if(avio_rl32(pb) == MKTAG('W', 'A', 'V', 'E')){ | 
| 100 | 2.04k |         uint32_t size, fsize; | 
| 101 | 2.04k |         c->has_sound = 1; | 
| 102 | 2.04k |         size = avio_rb32(pb); | 
| 103 | 2.04k |         c->vidpos = avio_tell(pb) + size; | 
| 104 | 2.04k |         avio_skip(pb, 16); | 
| 105 | 2.04k |         fsize = avio_rl32(pb); | 
| 106 |  |  | 
| 107 | 2.04k |         ast = avformat_new_stream(s, NULL); | 
| 108 | 2.04k |         if (!ast) | 
| 109 | 0 |             return AVERROR(ENOMEM); | 
| 110 | 2.04k |         ret = ff_get_wav_header(s, pb, ast->codecpar, fsize, 0); | 
| 111 | 2.04k |         if (ret < 0) | 
| 112 | 224 |             return ret; | 
| 113 | 1.82k |         if (ast->codecpar->sample_rate > 0) | 
| 114 | 1.80k |             avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate); | 
| 115 |  |         // find 'data' chunk | 
| 116 | 3.14k |         while(avio_tell(pb) < c->vidpos && !avio_feof(pb)){ | 
| 117 | 1.39k |             tag = avio_rl32(pb); | 
| 118 | 1.39k |             fsize = avio_rl32(pb); | 
| 119 | 1.39k |             if(tag == MKTAG('d', 'a', 't', 'a')) break; | 
| 120 | 1.32k |             avio_skip(pb, fsize); | 
| 121 | 1.32k |         } | 
| 122 | 1.82k |         c->bpc = (fsize + (int64_t)c->frames - 1) / c->frames; | 
| 123 | 1.82k |         if(ast->codecpar->block_align) { | 
| 124 | 1.05k |             if (c->bpc > INT_MAX - ast->codecpar->block_align + 1) | 
| 125 | 1 |                 return AVERROR_INVALIDDATA; | 
| 126 | 1.05k |             c->bpc = ((c->bpc - 1 + ast->codecpar->block_align) / ast->codecpar->block_align) * ast->codecpar->block_align; | 
| 127 | 1.05k |         } | 
| 128 | 1.82k |         c->bytes_left = fsize; | 
| 129 | 1.82k |         c->wavpos = avio_tell(pb); | 
| 130 | 1.82k |         avio_seek(pb, c->vidpos, SEEK_SET); | 
| 131 | 1.82k |     } | 
| 132 |  |  | 
| 133 |  |     /* now we are ready: build format streams */ | 
| 134 | 2.89k |     st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; | 
| 135 | 2.89k |     st->codecpar->codec_id   = AV_CODEC_ID_DXA; | 
| 136 | 2.89k |     st->codecpar->width      = w; | 
| 137 | 2.89k |     st->codecpar->height     = h; | 
| 138 | 2.89k |     av_reduce(&den, &num, den, num, (1UL<<31)-1); | 
| 139 | 2.89k |     avpriv_set_pts_info(st, 33, num, den); | 
| 140 |  |     /* flags & 0x80 means that image is interlaced, | 
| 141 |  |      * flags & 0x40 means that image has double height | 
| 142 |  |      * either way set true height | 
| 143 |  |      */ | 
| 144 | 2.89k |     if(flags & 0xC0){ | 
| 145 | 1.12k |         st->codecpar->height >>= 1; | 
| 146 | 1.12k |     } | 
| 147 | 2.89k |     c->readvid = !c->has_sound; | 
| 148 | 2.89k |     c->vidpos  = avio_tell(pb); | 
| 149 | 2.89k |     s->start_time = 0; | 
| 150 | 2.89k |     s->duration = av_rescale(c->frames, AV_TIME_BASE * (int64_t)num, den); | 
| 151 | 2.89k |     av_log(s, AV_LOG_DEBUG, "%d frame(s)\n",c->frames); | 
| 152 |  |  | 
| 153 | 2.89k |     return 0; | 
| 154 | 3.11k | } | 
| 155 |  |  | 
| 156 |  | static int dxa_read_packet(AVFormatContext *s, AVPacket *pkt) | 
| 157 | 182k | { | 
| 158 | 182k |     DXAContext *c = s->priv_data; | 
| 159 | 182k |     int ret; | 
| 160 | 182k |     uint32_t size; | 
| 161 | 182k |     uint8_t buf[DXA_EXTRA_SIZE], pal[768+4]; | 
| 162 | 182k |     int pal_size = 0; | 
| 163 |  |  | 
| 164 | 182k |     if(!c->readvid && c->has_sound && c->bytes_left){ | 
| 165 | 55.3k |         c->readvid = 1; | 
| 166 | 55.3k |         avio_seek(s->pb, c->wavpos, SEEK_SET); | 
| 167 | 55.3k |         size = FFMIN(c->bytes_left, c->bpc); | 
| 168 | 55.3k |         ret = av_get_packet(s->pb, pkt, size); | 
| 169 | 55.3k |         pkt->stream_index = 1; | 
| 170 | 55.3k |         if(ret != size) | 
| 171 | 915 |             return AVERROR(EIO); | 
| 172 | 54.4k |         c->bytes_left -= size; | 
| 173 | 54.4k |         c->wavpos = avio_tell(s->pb); | 
| 174 | 54.4k |         return 0; | 
| 175 | 55.3k |     } | 
| 176 | 127k |     avio_seek(s->pb, c->vidpos, SEEK_SET); | 
| 177 | 128k |     while(!avio_feof(s->pb) && c->frames){ | 
| 178 | 128k |         uint32_t tag; | 
| 179 | 128k |         if ((ret = avio_read(s->pb, buf, 4)) != 4) { | 
| 180 | 2.98k |             av_log(s, AV_LOG_ERROR, "failed reading chunk type\n"); | 
| 181 | 2.98k |             return ret < 0 ? ret : AVERROR_INVALIDDATA; | 
| 182 | 2.98k |         } | 
| 183 | 125k |         tag = AV_RL32(buf); | 
| 184 | 125k |         switch (tag) { | 
| 185 | 122k |         case MKTAG('N', 'U', 'L', 'L'): | 
| 186 | 122k |             if ((ret = av_new_packet(pkt, 4 + pal_size)) < 0) | 
| 187 | 0 |                 return ret; | 
| 188 | 122k |             pkt->stream_index = 0; | 
| 189 | 122k |             if(pal_size) memcpy(pkt->data, pal, pal_size); | 
| 190 | 122k |             memcpy(pkt->data + pal_size, buf, 4); | 
| 191 | 122k |             c->frames--; | 
| 192 | 122k |             c->vidpos = avio_tell(s->pb); | 
| 193 | 122k |             c->readvid = 0; | 
| 194 | 122k |             return 0; | 
| 195 | 732 |         case MKTAG('C', 'M', 'A', 'P'): | 
| 196 | 732 |             pal_size = 768+4; | 
| 197 | 732 |             memcpy(pal, buf, 4); | 
| 198 | 732 |             avio_read(s->pb, pal + 4, 768); | 
| 199 | 732 |             break; | 
| 200 | 982 |         case MKTAG('F', 'R', 'A', 'M'): | 
| 201 | 982 |             if ((ret = avio_read(s->pb, buf + 4, DXA_EXTRA_SIZE - 4)) != DXA_EXTRA_SIZE - 4) { | 
| 202 | 7 |                 av_log(s, AV_LOG_ERROR, "failed reading dxa_extra\n"); | 
| 203 | 7 |                 return ret < 0 ? ret : AVERROR_INVALIDDATA; | 
| 204 | 7 |             } | 
| 205 | 975 |             size = AV_RB32(buf + 5); | 
| 206 | 975 |             if(size > 0xFFFFFF){ | 
| 207 | 13 |                 av_log(s, AV_LOG_ERROR, "Frame size is too big: %"PRIu32"\n", | 
| 208 | 13 |                        size); | 
| 209 | 13 |                 return AVERROR_INVALIDDATA; | 
| 210 | 13 |             } | 
| 211 | 962 |             ret = av_new_packet(pkt, size + DXA_EXTRA_SIZE + pal_size); | 
| 212 | 962 |             if (ret < 0) | 
| 213 | 0 |                 return ret; | 
| 214 | 962 |             memcpy(pkt->data + pal_size, buf, DXA_EXTRA_SIZE); | 
| 215 | 962 |             ret = avio_read(s->pb, pkt->data + DXA_EXTRA_SIZE + pal_size, size); | 
| 216 | 962 |             if(ret != size){ | 
| 217 | 50 |                 return AVERROR(EIO); | 
| 218 | 50 |             } | 
| 219 | 912 |             if(pal_size) memcpy(pkt->data, pal, pal_size); | 
| 220 | 912 |             pkt->stream_index = 0; | 
| 221 | 912 |             c->frames--; | 
| 222 | 912 |             c->vidpos = avio_tell(s->pb); | 
| 223 | 912 |             c->readvid = 0; | 
| 224 | 912 |             return 0; | 
| 225 | 1.17k |         default: | 
| 226 | 1.17k |             av_log(s, AV_LOG_ERROR, "Unknown tag %s\n", av_fourcc2str(tag)); | 
| 227 | 1.17k |             return AVERROR_INVALIDDATA; | 
| 228 | 125k |         } | 
| 229 | 125k |     } | 
| 230 | 240 |     return AVERROR_EOF; | 
| 231 | 127k | } | 
| 232 |  |  | 
| 233 |  | const FFInputFormat ff_dxa_demuxer = { | 
| 234 |  |     .p.name         = "dxa", | 
| 235 |  |     .p.long_name    = NULL_IF_CONFIG_SMALL("DXA"), | 
| 236 |  |     .priv_data_size = sizeof(DXAContext), | 
| 237 |  |     .read_probe     = dxa_probe, | 
| 238 |  |     .read_header    = dxa_read_header, | 
| 239 |  |     .read_packet    = dxa_read_packet, | 
| 240 |  | }; |