diff options
Diffstat (limited to 'libavformat/ipmovie.c')
-rw-r--r-- | libavformat/ipmovie.c | 187 |
1 files changed, 107 insertions, 80 deletions
diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c index b719fed2b9..f9ab3e0d57 100644 --- a/libavformat/ipmovie.c +++ b/libavformat/ipmovie.c @@ -2,20 +2,20 @@ * Interplay MVE File Demuxer * Copyright (c) 2003 The FFmpeg project * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -78,7 +78,7 @@ #define PALETTE_COUNT 256 typedef struct IPMVEContext { - + AVFormatContext *avf; unsigned char *buf; int buf_size; @@ -117,9 +117,9 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, int chunk_type; - if (s->audio_chunk_offset) { + if (s->audio_chunk_offset && s->audio_channels && s->audio_bits) { if (s->audio_type == AV_CODEC_ID_NONE) { - av_log(NULL, AV_LOG_ERROR, "Can not read audio packet before" + av_log(s->avf, AV_LOG_ERROR, "Can not read audio packet before" "audio codec is known\n"); return CHUNK_BAD; } @@ -147,7 +147,7 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, s->audio_frame_count += (s->audio_chunk_size - 6 - s->audio_channels) / s->audio_channels; - av_log(NULL, AV_LOG_TRACE, "sending audio frame with pts %"PRId64" (%d audio frames)\n", + av_log(s->avf, AV_LOG_TRACE, "sending audio frame with pts %"PRId64" (%d audio frames)\n", pkt->pts, s->audio_frame_count); chunk_type = CHUNK_VIDEO; @@ -156,7 +156,7 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, /* send both the decode map and the video data together */ - if (av_new_packet(pkt, s->decode_map_chunk_size + s->video_chunk_size)) + if (av_new_packet(pkt, 2 + s->decode_map_chunk_size + s->video_chunk_size)) return CHUNK_NOMEM; if (s->has_palette) { @@ -178,7 +178,8 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, avio_seek(pb, s->decode_map_chunk_offset, SEEK_SET); s->decode_map_chunk_offset = 0; - if (avio_read(pb, pkt->data, s->decode_map_chunk_size) != + AV_WL16(pkt->data, s->decode_map_chunk_size); + if (avio_read(pb, pkt->data + 2, s->decode_map_chunk_size) != s->decode_map_chunk_size) { av_packet_unref(pkt); return CHUNK_EOF; @@ -187,7 +188,7 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, avio_seek(pb, s->video_chunk_offset, SEEK_SET); s->video_chunk_offset = 0; - if (avio_read(pb, pkt->data + s->decode_map_chunk_size, + if (avio_read(pb, pkt->data + 2 + s->decode_map_chunk_size, s->video_chunk_size) != s->video_chunk_size) { av_packet_unref(pkt); return CHUNK_EOF; @@ -196,7 +197,7 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, pkt->stream_index = s->video_stream_index; pkt->pts = s->video_pts; - av_log(NULL, AV_LOG_TRACE, "sending video frame with pts %"PRId64"\n", pkt->pts); + av_log(s->avf, AV_LOG_TRACE, "sending video frame with pts %"PRId64"\n", pkt->pts); s->video_pts += s->frame_pts_inc; @@ -212,6 +213,31 @@ static int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, return chunk_type; } +static int init_audio(AVFormatContext *s) +{ + IPMVEContext *ipmovie = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate); + ipmovie->audio_stream_index = st->index; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = ipmovie->audio_type; + st->codecpar->codec_tag = 0; /* no tag */ + st->codecpar->channels = ipmovie->audio_channels; + st->codecpar->channel_layout = st->codecpar->channels == 1 ? AV_CH_LAYOUT_MONO : + AV_CH_LAYOUT_STEREO; + st->codecpar->sample_rate = ipmovie->audio_sample_rate; + st->codecpar->bits_per_coded_sample = ipmovie->audio_bits; + st->codecpar->bit_rate = st->codecpar->channels * st->codecpar->sample_rate * + st->codecpar->bits_per_coded_sample; + if (st->codecpar->codec_id == AV_CODEC_ID_INTERPLAY_DPCM) + st->codecpar->bit_rate /= 2; + st->codecpar->block_align = st->codecpar->channels * st->codecpar->bits_per_coded_sample; + + return 0; +} + /* This function loads and processes a single chunk in an IP movie file. * It returns the type of chunk that was processed. */ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, @@ -237,7 +263,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, return chunk_type; /* read the next chunk, wherever the file happens to be pointing */ - if (pb->eof_reached) + if (avio_feof(pb)) return CHUNK_EOF; if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != CHUNK_PREAMBLE_SIZE) @@ -245,36 +271,36 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, chunk_size = AV_RL16(&chunk_preamble[0]); chunk_type = AV_RL16(&chunk_preamble[2]); - av_log(NULL, AV_LOG_TRACE, "chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size); + av_log(s->avf, AV_LOG_TRACE, "chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size); switch (chunk_type) { case CHUNK_INIT_AUDIO: - av_log(NULL, AV_LOG_TRACE, "initialize audio\n"); + av_log(s->avf, AV_LOG_TRACE, "initialize audio\n"); break; case CHUNK_AUDIO_ONLY: - av_log(NULL, AV_LOG_TRACE, "audio only\n"); + av_log(s->avf, AV_LOG_TRACE, "audio only\n"); break; case CHUNK_INIT_VIDEO: - av_log(NULL, AV_LOG_TRACE, "initialize video\n"); + av_log(s->avf, AV_LOG_TRACE, "initialize video\n"); break; case CHUNK_VIDEO: - av_log(NULL, AV_LOG_TRACE, "video (and audio)\n"); + av_log(s->avf, AV_LOG_TRACE, "video (and audio)\n"); break; case CHUNK_SHUTDOWN: - av_log(NULL, AV_LOG_TRACE, "shutdown\n"); + av_log(s->avf, AV_LOG_TRACE, "shutdown\n"); break; case CHUNK_END: - av_log(NULL, AV_LOG_TRACE, "end\n"); + av_log(s->avf, AV_LOG_TRACE, "end\n"); break; default: - av_log(NULL, AV_LOG_TRACE, "invalid chunk\n"); + av_log(s->avf, AV_LOG_TRACE, "invalid chunk\n"); chunk_type = CHUNK_BAD; break; @@ -283,7 +309,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) { /* read the next chunk, wherever the file happens to be pointing */ - if (pb->eof_reached) { + if (avio_feof(pb)) { chunk_type = CHUNK_EOF; break; } @@ -300,29 +326,29 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, chunk_size -= OPCODE_PREAMBLE_SIZE; chunk_size -= opcode_size; if (chunk_size < 0) { - av_log(NULL, AV_LOG_TRACE, "chunk_size countdown just went negative\n"); + av_log(s->avf, AV_LOG_TRACE, "chunk_size countdown just went negative\n"); chunk_type = CHUNK_BAD; break; } - av_log(NULL, AV_LOG_TRACE, " opcode type %02X, version %d, 0x%04X bytes: ", + av_log(s->avf, AV_LOG_TRACE, " opcode type %02X, version %d, 0x%04X bytes: ", opcode_type, opcode_version, opcode_size); switch (opcode_type) { case OPCODE_END_OF_STREAM: - av_log(NULL, AV_LOG_TRACE, "end of stream\n"); + av_log(s->avf, AV_LOG_TRACE, "end of stream\n"); avio_skip(pb, opcode_size); break; case OPCODE_END_OF_CHUNK: - av_log(NULL, AV_LOG_TRACE, "end of chunk\n"); + av_log(s->avf, AV_LOG_TRACE, "end of chunk\n"); avio_skip(pb, opcode_size); break; case OPCODE_CREATE_TIMER: - av_log(NULL, AV_LOG_TRACE, "create timer\n"); - if ((opcode_version > 0) || (opcode_size > 6)) { - av_log(NULL, AV_LOG_TRACE, "bad create_timer opcode\n"); + av_log(s->avf, AV_LOG_TRACE, "create timer\n"); + if ((opcode_version > 0) || (opcode_size != 6)) { + av_log(s->avf, AV_LOG_TRACE, "bad create_timer opcode\n"); chunk_type = CHUNK_BAD; break; } @@ -332,15 +358,15 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, break; } s->frame_pts_inc = ((uint64_t)AV_RL32(&scratch[0])) * AV_RL16(&scratch[4]); - av_log(NULL, AV_LOG_TRACE, " %.2f frames/second (timer div = %d, subdiv = %d)\n", + av_log(s->avf, AV_LOG_TRACE, " %.2f frames/second (timer div = %d, subdiv = %d)\n", 1000000.0 / s->frame_pts_inc, AV_RL32(&scratch[0]), AV_RL16(&scratch[4])); break; case OPCODE_INIT_AUDIO_BUFFERS: - av_log(NULL, AV_LOG_TRACE, "initialize audio buffers\n"); - if ((opcode_version > 1) || (opcode_size > 10)) { - av_log(NULL, AV_LOG_TRACE, "bad init_audio_buffers opcode\n"); + av_log(s->avf, AV_LOG_TRACE, "initialize audio buffers\n"); + if (opcode_version > 1 || opcode_size > 10 || opcode_size < 6) { + av_log(s->avf, AV_LOG_TRACE, "bad init_audio_buffers opcode\n"); chunk_type = CHUNK_BAD; break; } @@ -362,7 +388,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, s->audio_type = AV_CODEC_ID_PCM_S16LE; else s->audio_type = AV_CODEC_ID_PCM_U8; - av_log(NULL, AV_LOG_TRACE, "audio: %d bits, %d Hz, %s, %s format\n", + av_log(s->avf, AV_LOG_TRACE, "audio: %d bits, %d Hz, %s, %s format\n", s->audio_bits, s->audio_sample_rate, (s->audio_channels == 2) ? "stereo" : "mono", (s->audio_type == AV_CODEC_ID_INTERPLAY_DPCM) ? @@ -370,14 +396,16 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, break; case OPCODE_START_STOP_AUDIO: - av_log(NULL, AV_LOG_TRACE, "start/stop audio\n"); + av_log(s->avf, AV_LOG_TRACE, "start/stop audio\n"); avio_skip(pb, opcode_size); break; case OPCODE_INIT_VIDEO_BUFFERS: - av_log(NULL, AV_LOG_TRACE, "initialize video buffers\n"); - if ((opcode_version > 2) || (opcode_size > 8)) { - av_log(NULL, AV_LOG_TRACE, "bad init_video_buffers opcode\n"); + av_log(s->avf, AV_LOG_TRACE, "initialize video buffers\n"); + if ((opcode_version > 2) || (opcode_size > 8) || opcode_size < 4 + || opcode_version == 2 && opcode_size < 8 + ) { + av_log(s->avf, AV_LOG_TRACE, "bad init_video_buffers opcode\n"); chunk_type = CHUNK_BAD; break; } @@ -401,7 +429,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, } else { s->video_bpp = 16; } - av_log(NULL, AV_LOG_TRACE, "video resolution: %d x %d\n", + av_log(s->avf, AV_LOG_TRACE, "video resolution: %d x %d\n", s->video_width, s->video_height); break; @@ -412,17 +440,17 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, case OPCODE_UNKNOWN_13: case OPCODE_UNKNOWN_14: case OPCODE_UNKNOWN_15: - av_log(NULL, AV_LOG_TRACE, "unknown (but documented) opcode %02X\n", opcode_type); + av_log(s->avf, AV_LOG_TRACE, "unknown (but documented) opcode %02X\n", opcode_type); avio_skip(pb, opcode_size); break; case OPCODE_SEND_BUFFER: - av_log(NULL, AV_LOG_TRACE, "send buffer\n"); + av_log(s->avf, AV_LOG_TRACE, "send buffer\n"); avio_skip(pb, opcode_size); break; case OPCODE_AUDIO_FRAME: - av_log(NULL, AV_LOG_TRACE, "audio frame\n"); + av_log(s->avf, AV_LOG_TRACE, "audio frame\n"); /* log position and move on for now */ s->audio_chunk_offset = avio_tell(pb); @@ -431,26 +459,26 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, break; case OPCODE_SILENCE_FRAME: - av_log(NULL, AV_LOG_TRACE, "silence frame\n"); + av_log(s->avf, AV_LOG_TRACE, "silence frame\n"); avio_skip(pb, opcode_size); break; case OPCODE_INIT_VIDEO_MODE: - av_log(NULL, AV_LOG_TRACE, "initialize video mode\n"); + av_log(s->avf, AV_LOG_TRACE, "initialize video mode\n"); avio_skip(pb, opcode_size); break; case OPCODE_CREATE_GRADIENT: - av_log(NULL, AV_LOG_TRACE, "create gradient\n"); + av_log(s->avf, AV_LOG_TRACE, "create gradient\n"); avio_skip(pb, opcode_size); break; case OPCODE_SET_PALETTE: - av_log(NULL, AV_LOG_TRACE, "set palette\n"); + av_log(s->avf, AV_LOG_TRACE, "set palette\n"); /* check for the logical maximum palette size * (3 * 256 + 4 bytes) */ - if (opcode_size > 0x304) { - av_log(NULL, AV_LOG_TRACE, "demux_ipmovie: set_palette opcode too large\n"); + if (opcode_size > 0x304 || opcode_size < 4) { + av_log(s->avf, AV_LOG_TRACE, "demux_ipmovie: set_palette opcode with invalid size\n"); chunk_type = CHUNK_BAD; break; } @@ -463,8 +491,9 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, first_color = AV_RL16(&scratch[0]); last_color = first_color + AV_RL16(&scratch[2]) - 1; /* sanity check (since they are 16 bit values) */ - if ((first_color > 0xFF) || (last_color > 0xFF)) { - av_log(NULL, AV_LOG_TRACE, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n", + if ( (first_color > 0xFF) || (last_color > 0xFF) + || (last_color - first_color + 1)*3 + 4 > opcode_size) { + av_log(s->avf, AV_LOG_TRACE, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n", first_color, last_color); chunk_type = CHUNK_BAD; break; @@ -476,18 +505,19 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, r = scratch[j++] * 4; g = scratch[j++] * 4; b = scratch[j++] * 4; - s->palette[i] = (r << 16) | (g << 8) | (b); + s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b); + s->palette[i] |= s->palette[i] >> 6 & 0x30303; } s->has_palette = 1; break; case OPCODE_SET_PALETTE_COMPRESSED: - av_log(NULL, AV_LOG_TRACE, "set palette compressed\n"); + av_log(s->avf, AV_LOG_TRACE, "set palette compressed\n"); avio_skip(pb, opcode_size); break; case OPCODE_SET_DECODING_MAP: - av_log(NULL, AV_LOG_TRACE, "set decoding map\n"); + av_log(s->avf, AV_LOG_TRACE, "set decoding map\n"); /* log position and move on for now */ s->decode_map_chunk_offset = avio_tell(pb); @@ -496,7 +526,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, break; case OPCODE_VIDEO_DATA: - av_log(NULL, AV_LOG_TRACE, "set video data\n"); + av_log(s->avf, AV_LOG_TRACE, "set video data\n"); /* log position and move on for now */ s->video_chunk_offset = avio_tell(pb); @@ -505,13 +535,16 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, break; default: - av_log(NULL, AV_LOG_TRACE, "*** unknown opcode type\n"); + av_log(s->avf, AV_LOG_TRACE, "*** unknown opcode type\n"); chunk_type = CHUNK_BAD; break; } } + if (s->avf->nb_streams == 1 && s->audio_type) + init_audio(s->avf); + /* make a note of where the stream is sitting */ s->next_chunk_offset = avio_tell(pb); @@ -526,11 +559,12 @@ static const char signature[] = "Interplay MVE File\x1A\0\x1A"; static int ipmovie_probe(AVProbeData *p) { - uint8_t *b = p->buf; - uint8_t *b_end = p->buf + p->buf_size - sizeof(signature); + const uint8_t *b = p->buf; + const uint8_t *b_end = p->buf + p->buf_size - sizeof(signature); do { - if (memcmp(b++, signature, sizeof(signature)) == 0) + if (b[0] == signature[0] && memcmp(b, signature, sizeof(signature)) == 0) return AVPROBE_SCORE_MAX; + b++; } while (b < b_end); return 0; @@ -543,14 +577,16 @@ static int ipmovie_read_header(AVFormatContext *s) AVPacket pkt; AVStream *st; unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; - int chunk_type; + int chunk_type, i; uint8_t signature_buffer[sizeof(signature)]; + ipmovie->avf = s; + avio_read(pb, signature_buffer, sizeof(signature_buffer)); while (memcmp(signature_buffer, signature, sizeof(signature))) { memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1); signature_buffer[sizeof(signature_buffer) - 1] = avio_r8(pb); - if (pb->eof_reached) + if (avio_feof(pb)) return AVERROR_EOF; } /* initialize private context members */ @@ -561,6 +597,9 @@ static int ipmovie_read_header(AVFormatContext *s) /* on the first read, this will position the stream at the first chunk */ ipmovie->next_chunk_offset = avio_tell(pb) + 4; + for (i = 0; i < 256; i++) + ipmovie->palette[i] = 0xFFU << 24; + /* process the first chunk which should be CHUNK_INIT_VIDEO */ if (process_ipmovie_chunk(ipmovie, pb, &pkt) != CHUNK_INIT_VIDEO) return AVERROR_INVALIDDATA; @@ -592,25 +631,9 @@ static int ipmovie_read_header(AVFormatContext *s) st->codecpar->bits_per_coded_sample = ipmovie->video_bpp; if (ipmovie->audio_type) { - st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); - avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate); - ipmovie->audio_stream_index = st->index; - st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; - st->codecpar->codec_id = ipmovie->audio_type; - st->codecpar->codec_tag = 0; /* no tag */ - st->codecpar->channels = ipmovie->audio_channels; - st->codecpar->channel_layout = st->codecpar->channels == 1 ? AV_CH_LAYOUT_MONO : - AV_CH_LAYOUT_STEREO; - st->codecpar->sample_rate = ipmovie->audio_sample_rate; - st->codecpar->bits_per_coded_sample = ipmovie->audio_bits; - st->codecpar->bit_rate = st->codecpar->channels * st->codecpar->sample_rate * - st->codecpar->bits_per_coded_sample; - if (st->codecpar->codec_id == AV_CODEC_ID_INTERPLAY_DPCM) - st->codecpar->bit_rate /= 2; - st->codecpar->block_align = st->codecpar->channels * st->codecpar->bits_per_coded_sample; - } + return init_audio(s); + } else + s->ctx_flags |= AVFMTCTX_NOHEADER; return 0; } @@ -622,6 +645,7 @@ static int ipmovie_read_packet(AVFormatContext *s, AVIOContext *pb = s->pb; int ret; + for (;;) { ret = process_ipmovie_chunk(ipmovie, pb, pkt); if (ret == CHUNK_BAD) ret = AVERROR_INVALIDDATA; @@ -631,10 +655,13 @@ static int ipmovie_read_packet(AVFormatContext *s, ret = AVERROR(ENOMEM); else if (ret == CHUNK_VIDEO) ret = 0; + else if (ret == CHUNK_INIT_VIDEO || ret == CHUNK_INIT_AUDIO) + continue; else - ret = -1; + continue; return ret; + } } AVInputFormat ff_ipmovie_demuxer = { |