1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Interplay MVE File Demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2003 The FFmpeg project 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * Interplay MVE file demuxer 25cabdff1aSopenharmony_ci * by Mike Melanson (melanson@pcisys.net) 26cabdff1aSopenharmony_ci * For more information regarding the Interplay MVE file format, visit: 27cabdff1aSopenharmony_ci * http://www.pcisys.net/~melanson/codecs/ 28cabdff1aSopenharmony_ci * The aforementioned site also contains a command line utility for parsing 29cabdff1aSopenharmony_ci * IP MVE files so that you can get a good idea of the typical structure of 30cabdff1aSopenharmony_ci * such files. This demuxer is not the best example to use if you are trying 31cabdff1aSopenharmony_ci * to write your own as it uses a rather roundabout approach for splitting 32cabdff1aSopenharmony_ci * up and sending out the chunks. 33cabdff1aSopenharmony_ci */ 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 36cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 37cabdff1aSopenharmony_ci#include "avformat.h" 38cabdff1aSopenharmony_ci#include "demux.h" 39cabdff1aSopenharmony_ci#include "internal.h" 40cabdff1aSopenharmony_ci 41cabdff1aSopenharmony_ci#define CHUNK_PREAMBLE_SIZE 4 42cabdff1aSopenharmony_ci#define OPCODE_PREAMBLE_SIZE 4 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_ci#define CHUNK_INIT_AUDIO 0x0000 45cabdff1aSopenharmony_ci#define CHUNK_AUDIO_ONLY 0x0001 46cabdff1aSopenharmony_ci#define CHUNK_INIT_VIDEO 0x0002 47cabdff1aSopenharmony_ci#define CHUNK_VIDEO 0x0003 48cabdff1aSopenharmony_ci#define CHUNK_SHUTDOWN 0x0004 49cabdff1aSopenharmony_ci#define CHUNK_END 0x0005 50cabdff1aSopenharmony_ci/* these last types are used internally */ 51cabdff1aSopenharmony_ci#define CHUNK_HAVE_PACKET 0xFFFB 52cabdff1aSopenharmony_ci#define CHUNK_DONE 0xFFFC 53cabdff1aSopenharmony_ci#define CHUNK_NOMEM 0xFFFD 54cabdff1aSopenharmony_ci#define CHUNK_EOF 0xFFFE 55cabdff1aSopenharmony_ci#define CHUNK_BAD 0xFFFF 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_ci#define OPCODE_END_OF_STREAM 0x00 58cabdff1aSopenharmony_ci#define OPCODE_END_OF_CHUNK 0x01 59cabdff1aSopenharmony_ci#define OPCODE_CREATE_TIMER 0x02 60cabdff1aSopenharmony_ci#define OPCODE_INIT_AUDIO_BUFFERS 0x03 61cabdff1aSopenharmony_ci#define OPCODE_START_STOP_AUDIO 0x04 62cabdff1aSopenharmony_ci#define OPCODE_INIT_VIDEO_BUFFERS 0x05 63cabdff1aSopenharmony_ci#define OPCODE_VIDEO_DATA_06 0x06 64cabdff1aSopenharmony_ci#define OPCODE_SEND_BUFFER 0x07 65cabdff1aSopenharmony_ci#define OPCODE_AUDIO_FRAME 0x08 66cabdff1aSopenharmony_ci#define OPCODE_SILENCE_FRAME 0x09 67cabdff1aSopenharmony_ci#define OPCODE_INIT_VIDEO_MODE 0x0A 68cabdff1aSopenharmony_ci#define OPCODE_CREATE_GRADIENT 0x0B 69cabdff1aSopenharmony_ci#define OPCODE_SET_PALETTE 0x0C 70cabdff1aSopenharmony_ci#define OPCODE_SET_PALETTE_COMPRESSED 0x0D 71cabdff1aSopenharmony_ci#define OPCODE_SET_SKIP_MAP 0x0E 72cabdff1aSopenharmony_ci#define OPCODE_SET_DECODING_MAP 0x0F 73cabdff1aSopenharmony_ci#define OPCODE_VIDEO_DATA_10 0x10 74cabdff1aSopenharmony_ci#define OPCODE_VIDEO_DATA_11 0x11 75cabdff1aSopenharmony_ci#define OPCODE_UNKNOWN_12 0x12 76cabdff1aSopenharmony_ci#define OPCODE_UNKNOWN_13 0x13 77cabdff1aSopenharmony_ci#define OPCODE_UNKNOWN_14 0x14 78cabdff1aSopenharmony_ci#define OPCODE_UNKNOWN_15 0x15 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_ci#define PALETTE_COUNT 256 81cabdff1aSopenharmony_ci 82cabdff1aSopenharmony_citypedef struct IPMVEContext { 83cabdff1aSopenharmony_ci AVFormatContext *avf; 84cabdff1aSopenharmony_ci unsigned char *buf; 85cabdff1aSopenharmony_ci int buf_size; 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci uint64_t frame_pts_inc; 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci unsigned int video_bpp; 90cabdff1aSopenharmony_ci unsigned int video_width; 91cabdff1aSopenharmony_ci unsigned int video_height; 92cabdff1aSopenharmony_ci int64_t video_pts; 93cabdff1aSopenharmony_ci uint32_t palette[256]; 94cabdff1aSopenharmony_ci int has_palette; 95cabdff1aSopenharmony_ci int changed; 96cabdff1aSopenharmony_ci uint8_t send_buffer; 97cabdff1aSopenharmony_ci uint8_t frame_format; 98cabdff1aSopenharmony_ci 99cabdff1aSopenharmony_ci unsigned int audio_bits; 100cabdff1aSopenharmony_ci unsigned int audio_channels; 101cabdff1aSopenharmony_ci unsigned int audio_sample_rate; 102cabdff1aSopenharmony_ci enum AVCodecID audio_type; 103cabdff1aSopenharmony_ci unsigned int audio_frame_count; 104cabdff1aSopenharmony_ci 105cabdff1aSopenharmony_ci int video_stream_index; 106cabdff1aSopenharmony_ci int audio_stream_index; 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci int64_t audio_chunk_offset; 109cabdff1aSopenharmony_ci int audio_chunk_size; 110cabdff1aSopenharmony_ci int64_t video_chunk_offset; 111cabdff1aSopenharmony_ci int video_chunk_size; 112cabdff1aSopenharmony_ci int64_t skip_map_chunk_offset; 113cabdff1aSopenharmony_ci int skip_map_chunk_size; 114cabdff1aSopenharmony_ci int64_t decode_map_chunk_offset; 115cabdff1aSopenharmony_ci int decode_map_chunk_size; 116cabdff1aSopenharmony_ci 117cabdff1aSopenharmony_ci int64_t next_chunk_offset; 118cabdff1aSopenharmony_ci 119cabdff1aSopenharmony_ci} IPMVEContext; 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_cistatic int load_ipmovie_packet(IPMVEContext *s, AVIOContext *pb, 122cabdff1aSopenharmony_ci AVPacket *pkt) { 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci int chunk_type; 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci if (s->audio_chunk_offset && s->audio_channels && s->audio_bits) { 127cabdff1aSopenharmony_ci if (s->audio_type == AV_CODEC_ID_NONE) { 128cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_ERROR, "Can not read audio packet before" 129cabdff1aSopenharmony_ci "audio codec is known\n"); 130cabdff1aSopenharmony_ci return CHUNK_BAD; 131cabdff1aSopenharmony_ci } 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci /* adjust for PCM audio by skipping chunk header */ 134cabdff1aSopenharmony_ci if (s->audio_type != AV_CODEC_ID_INTERPLAY_DPCM) { 135cabdff1aSopenharmony_ci s->audio_chunk_offset += 6; 136cabdff1aSopenharmony_ci s->audio_chunk_size -= 6; 137cabdff1aSopenharmony_ci } 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci avio_seek(pb, s->audio_chunk_offset, SEEK_SET); 140cabdff1aSopenharmony_ci s->audio_chunk_offset = 0; 141cabdff1aSopenharmony_ci 142cabdff1aSopenharmony_ci if (s->audio_chunk_size != av_get_packet(pb, pkt, s->audio_chunk_size)) 143cabdff1aSopenharmony_ci return CHUNK_EOF; 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci pkt->stream_index = s->audio_stream_index; 146cabdff1aSopenharmony_ci pkt->pts = s->audio_frame_count; 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_ci /* audio frame maintenance */ 149cabdff1aSopenharmony_ci if (s->audio_type != AV_CODEC_ID_INTERPLAY_DPCM) 150cabdff1aSopenharmony_ci s->audio_frame_count += 151cabdff1aSopenharmony_ci (s->audio_chunk_size / s->audio_channels / (s->audio_bits / 8)); 152cabdff1aSopenharmony_ci else 153cabdff1aSopenharmony_ci s->audio_frame_count += 154cabdff1aSopenharmony_ci (s->audio_chunk_size - 6 - s->audio_channels) / s->audio_channels; 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "sending audio frame with pts %"PRId64" (%d audio frames)\n", 157cabdff1aSopenharmony_ci pkt->pts, s->audio_frame_count); 158cabdff1aSopenharmony_ci 159cabdff1aSopenharmony_ci chunk_type = CHUNK_HAVE_PACKET; 160cabdff1aSopenharmony_ci 161cabdff1aSopenharmony_ci } else if (s->frame_format) { 162cabdff1aSopenharmony_ci 163cabdff1aSopenharmony_ci /* send the frame format, decode map, the video data, skip map, and the send_buffer flag together */ 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci if (av_new_packet(pkt, 8 + s->decode_map_chunk_size + s->video_chunk_size + s->skip_map_chunk_size)) 166cabdff1aSopenharmony_ci return CHUNK_NOMEM; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_ci if (s->has_palette) { 169cabdff1aSopenharmony_ci uint8_t *pal; 170cabdff1aSopenharmony_ci 171cabdff1aSopenharmony_ci pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, 172cabdff1aSopenharmony_ci AVPALETTE_SIZE); 173cabdff1aSopenharmony_ci if (pal) { 174cabdff1aSopenharmony_ci memcpy(pal, s->palette, AVPALETTE_SIZE); 175cabdff1aSopenharmony_ci s->has_palette = 0; 176cabdff1aSopenharmony_ci } 177cabdff1aSopenharmony_ci } 178cabdff1aSopenharmony_ci 179cabdff1aSopenharmony_ci if (s->changed) { 180cabdff1aSopenharmony_ci ff_add_param_change(pkt, 0, 0, 0, s->video_width, s->video_height); 181cabdff1aSopenharmony_ci s->changed = 0; 182cabdff1aSopenharmony_ci } 183cabdff1aSopenharmony_ci 184cabdff1aSopenharmony_ci AV_WL8(pkt->data, s->frame_format); 185cabdff1aSopenharmony_ci AV_WL8(pkt->data + 1, s->send_buffer); 186cabdff1aSopenharmony_ci AV_WL16(pkt->data + 2, s->video_chunk_size); 187cabdff1aSopenharmony_ci AV_WL16(pkt->data + 4, s->decode_map_chunk_size); 188cabdff1aSopenharmony_ci AV_WL16(pkt->data + 6, s->skip_map_chunk_size); 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci s->frame_format = 0; 191cabdff1aSopenharmony_ci s->send_buffer = 0; 192cabdff1aSopenharmony_ci 193cabdff1aSopenharmony_ci pkt->pos = s->video_chunk_offset; 194cabdff1aSopenharmony_ci avio_seek(pb, s->video_chunk_offset, SEEK_SET); 195cabdff1aSopenharmony_ci s->video_chunk_offset = 0; 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ci if (avio_read(pb, pkt->data + 8, s->video_chunk_size) != 198cabdff1aSopenharmony_ci s->video_chunk_size) { 199cabdff1aSopenharmony_ci return CHUNK_EOF; 200cabdff1aSopenharmony_ci } 201cabdff1aSopenharmony_ci 202cabdff1aSopenharmony_ci if (s->decode_map_chunk_size) { 203cabdff1aSopenharmony_ci pkt->pos = s->decode_map_chunk_offset; 204cabdff1aSopenharmony_ci avio_seek(pb, s->decode_map_chunk_offset, SEEK_SET); 205cabdff1aSopenharmony_ci s->decode_map_chunk_offset = 0; 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ci if (avio_read(pb, pkt->data + 8 + s->video_chunk_size, 208cabdff1aSopenharmony_ci s->decode_map_chunk_size) != s->decode_map_chunk_size) { 209cabdff1aSopenharmony_ci return CHUNK_EOF; 210cabdff1aSopenharmony_ci } 211cabdff1aSopenharmony_ci } 212cabdff1aSopenharmony_ci 213cabdff1aSopenharmony_ci if (s->skip_map_chunk_size) { 214cabdff1aSopenharmony_ci pkt->pos = s->skip_map_chunk_offset; 215cabdff1aSopenharmony_ci avio_seek(pb, s->skip_map_chunk_offset, SEEK_SET); 216cabdff1aSopenharmony_ci s->skip_map_chunk_offset = 0; 217cabdff1aSopenharmony_ci 218cabdff1aSopenharmony_ci if (avio_read(pb, pkt->data + 8 + s->video_chunk_size + s->decode_map_chunk_size, 219cabdff1aSopenharmony_ci s->skip_map_chunk_size) != s->skip_map_chunk_size) { 220cabdff1aSopenharmony_ci return CHUNK_EOF; 221cabdff1aSopenharmony_ci } 222cabdff1aSopenharmony_ci } 223cabdff1aSopenharmony_ci 224cabdff1aSopenharmony_ci s->video_chunk_size = 0; 225cabdff1aSopenharmony_ci s->decode_map_chunk_size = 0; 226cabdff1aSopenharmony_ci s->skip_map_chunk_size = 0; 227cabdff1aSopenharmony_ci 228cabdff1aSopenharmony_ci pkt->stream_index = s->video_stream_index; 229cabdff1aSopenharmony_ci pkt->pts = s->video_pts; 230cabdff1aSopenharmony_ci 231cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "sending video frame with pts %"PRId64"\n", pkt->pts); 232cabdff1aSopenharmony_ci 233cabdff1aSopenharmony_ci s->video_pts += s->frame_pts_inc; 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci chunk_type = CHUNK_HAVE_PACKET; 236cabdff1aSopenharmony_ci 237cabdff1aSopenharmony_ci } else { 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci avio_seek(pb, s->next_chunk_offset, SEEK_SET); 240cabdff1aSopenharmony_ci chunk_type = CHUNK_DONE; 241cabdff1aSopenharmony_ci 242cabdff1aSopenharmony_ci } 243cabdff1aSopenharmony_ci 244cabdff1aSopenharmony_ci return chunk_type; 245cabdff1aSopenharmony_ci} 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_cistatic int init_audio(AVFormatContext *s) 248cabdff1aSopenharmony_ci{ 249cabdff1aSopenharmony_ci IPMVEContext *ipmovie = s->priv_data; 250cabdff1aSopenharmony_ci AVStream *st = avformat_new_stream(s, NULL); 251cabdff1aSopenharmony_ci if (!st) 252cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 253cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 32, 1, ipmovie->audio_sample_rate); 254cabdff1aSopenharmony_ci ipmovie->audio_stream_index = st->index; 255cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 256cabdff1aSopenharmony_ci st->codecpar->codec_id = ipmovie->audio_type; 257cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; /* no tag */ 258cabdff1aSopenharmony_ci av_channel_layout_default(&st->codecpar->ch_layout, ipmovie->audio_channels); 259cabdff1aSopenharmony_ci st->codecpar->sample_rate = ipmovie->audio_sample_rate; 260cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample = ipmovie->audio_bits; 261cabdff1aSopenharmony_ci st->codecpar->bit_rate = ipmovie->audio_channels * st->codecpar->sample_rate * 262cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample; 263cabdff1aSopenharmony_ci if (st->codecpar->codec_id == AV_CODEC_ID_INTERPLAY_DPCM) 264cabdff1aSopenharmony_ci st->codecpar->bit_rate /= 2; 265cabdff1aSopenharmony_ci st->codecpar->block_align = ipmovie->audio_channels * st->codecpar->bits_per_coded_sample; 266cabdff1aSopenharmony_ci 267cabdff1aSopenharmony_ci return 0; 268cabdff1aSopenharmony_ci} 269cabdff1aSopenharmony_ci 270cabdff1aSopenharmony_ci/* This function loads and processes a single chunk in an IP movie file. 271cabdff1aSopenharmony_ci * It returns the type of chunk that was processed. */ 272cabdff1aSopenharmony_cistatic int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, 273cabdff1aSopenharmony_ci AVPacket *pkt) 274cabdff1aSopenharmony_ci{ 275cabdff1aSopenharmony_ci unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; 276cabdff1aSopenharmony_ci int chunk_type; 277cabdff1aSopenharmony_ci int chunk_size; 278cabdff1aSopenharmony_ci unsigned char opcode_preamble[OPCODE_PREAMBLE_SIZE]; 279cabdff1aSopenharmony_ci unsigned char opcode_type; 280cabdff1aSopenharmony_ci unsigned char opcode_version; 281cabdff1aSopenharmony_ci int opcode_size; 282cabdff1aSopenharmony_ci unsigned char scratch[1024]; 283cabdff1aSopenharmony_ci int i, j; 284cabdff1aSopenharmony_ci int first_color, last_color; 285cabdff1aSopenharmony_ci int audio_flags; 286cabdff1aSopenharmony_ci unsigned char r, g, b; 287cabdff1aSopenharmony_ci unsigned int width, height; 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ci /* see if there are any pending packets */ 290cabdff1aSopenharmony_ci chunk_type = load_ipmovie_packet(s, pb, pkt); 291cabdff1aSopenharmony_ci if (chunk_type != CHUNK_DONE) 292cabdff1aSopenharmony_ci return chunk_type; 293cabdff1aSopenharmony_ci 294cabdff1aSopenharmony_ci /* read the next chunk, wherever the file happens to be pointing */ 295cabdff1aSopenharmony_ci if (avio_feof(pb)) 296cabdff1aSopenharmony_ci return CHUNK_EOF; 297cabdff1aSopenharmony_ci if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != 298cabdff1aSopenharmony_ci CHUNK_PREAMBLE_SIZE) 299cabdff1aSopenharmony_ci return CHUNK_BAD; 300cabdff1aSopenharmony_ci chunk_size = AV_RL16(&chunk_preamble[0]); 301cabdff1aSopenharmony_ci chunk_type = AV_RL16(&chunk_preamble[2]); 302cabdff1aSopenharmony_ci 303cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "chunk type 0x%04X, 0x%04X bytes: ", chunk_type, chunk_size); 304cabdff1aSopenharmony_ci 305cabdff1aSopenharmony_ci switch (chunk_type) { 306cabdff1aSopenharmony_ci 307cabdff1aSopenharmony_ci case CHUNK_INIT_AUDIO: 308cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "initialize audio\n"); 309cabdff1aSopenharmony_ci break; 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ci case CHUNK_AUDIO_ONLY: 312cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "audio only\n"); 313cabdff1aSopenharmony_ci break; 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci case CHUNK_INIT_VIDEO: 316cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "initialize video\n"); 317cabdff1aSopenharmony_ci break; 318cabdff1aSopenharmony_ci 319cabdff1aSopenharmony_ci case CHUNK_VIDEO: 320cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "video (and audio)\n"); 321cabdff1aSopenharmony_ci break; 322cabdff1aSopenharmony_ci 323cabdff1aSopenharmony_ci case CHUNK_SHUTDOWN: 324cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "shutdown\n"); 325cabdff1aSopenharmony_ci break; 326cabdff1aSopenharmony_ci 327cabdff1aSopenharmony_ci case CHUNK_END: 328cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "end\n"); 329cabdff1aSopenharmony_ci break; 330cabdff1aSopenharmony_ci 331cabdff1aSopenharmony_ci default: 332cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "invalid chunk\n"); 333cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 334cabdff1aSopenharmony_ci break; 335cabdff1aSopenharmony_ci 336cabdff1aSopenharmony_ci } 337cabdff1aSopenharmony_ci 338cabdff1aSopenharmony_ci while ((chunk_size > 0) && (chunk_type != CHUNK_BAD)) { 339cabdff1aSopenharmony_ci 340cabdff1aSopenharmony_ci /* read the next chunk, wherever the file happens to be pointing */ 341cabdff1aSopenharmony_ci if (avio_feof(pb)) { 342cabdff1aSopenharmony_ci chunk_type = CHUNK_EOF; 343cabdff1aSopenharmony_ci break; 344cabdff1aSopenharmony_ci } 345cabdff1aSopenharmony_ci if (avio_read(pb, opcode_preamble, CHUNK_PREAMBLE_SIZE) != 346cabdff1aSopenharmony_ci CHUNK_PREAMBLE_SIZE) { 347cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 348cabdff1aSopenharmony_ci break; 349cabdff1aSopenharmony_ci } 350cabdff1aSopenharmony_ci 351cabdff1aSopenharmony_ci opcode_size = AV_RL16(&opcode_preamble[0]); 352cabdff1aSopenharmony_ci opcode_type = opcode_preamble[2]; 353cabdff1aSopenharmony_ci opcode_version = opcode_preamble[3]; 354cabdff1aSopenharmony_ci 355cabdff1aSopenharmony_ci chunk_size -= OPCODE_PREAMBLE_SIZE; 356cabdff1aSopenharmony_ci chunk_size -= opcode_size; 357cabdff1aSopenharmony_ci if (chunk_size < 0) { 358cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "chunk_size countdown just went negative\n"); 359cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 360cabdff1aSopenharmony_ci break; 361cabdff1aSopenharmony_ci } 362cabdff1aSopenharmony_ci 363cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, " opcode type %02X, version %d, 0x%04X bytes: ", 364cabdff1aSopenharmony_ci opcode_type, opcode_version, opcode_size); 365cabdff1aSopenharmony_ci switch (opcode_type) { 366cabdff1aSopenharmony_ci 367cabdff1aSopenharmony_ci case OPCODE_END_OF_STREAM: 368cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "end of stream\n"); 369cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 370cabdff1aSopenharmony_ci break; 371cabdff1aSopenharmony_ci 372cabdff1aSopenharmony_ci case OPCODE_END_OF_CHUNK: 373cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "end of chunk\n"); 374cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 375cabdff1aSopenharmony_ci break; 376cabdff1aSopenharmony_ci 377cabdff1aSopenharmony_ci case OPCODE_CREATE_TIMER: 378cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "create timer\n"); 379cabdff1aSopenharmony_ci if ((opcode_version > 0) || (opcode_size != 6)) { 380cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "bad create_timer opcode\n"); 381cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 382cabdff1aSopenharmony_ci break; 383cabdff1aSopenharmony_ci } 384cabdff1aSopenharmony_ci if (avio_read(pb, scratch, opcode_size) != 385cabdff1aSopenharmony_ci opcode_size) { 386cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 387cabdff1aSopenharmony_ci break; 388cabdff1aSopenharmony_ci } 389cabdff1aSopenharmony_ci s->frame_pts_inc = ((uint64_t)AV_RL32(&scratch[0])) * AV_RL16(&scratch[4]); 390cabdff1aSopenharmony_ci break; 391cabdff1aSopenharmony_ci 392cabdff1aSopenharmony_ci case OPCODE_INIT_AUDIO_BUFFERS: 393cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "initialize audio buffers\n"); 394cabdff1aSopenharmony_ci if (opcode_version > 1 || opcode_size > 10 || opcode_size < 6) { 395cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "bad init_audio_buffers opcode\n"); 396cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 397cabdff1aSopenharmony_ci break; 398cabdff1aSopenharmony_ci } 399cabdff1aSopenharmony_ci if (avio_read(pb, scratch, opcode_size) != 400cabdff1aSopenharmony_ci opcode_size) { 401cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 402cabdff1aSopenharmony_ci break; 403cabdff1aSopenharmony_ci } 404cabdff1aSopenharmony_ci s->audio_sample_rate = AV_RL16(&scratch[4]); 405cabdff1aSopenharmony_ci audio_flags = AV_RL16(&scratch[2]); 406cabdff1aSopenharmony_ci /* bit 0 of the flags: 0 = mono, 1 = stereo */ 407cabdff1aSopenharmony_ci s->audio_channels = (audio_flags & 1) + 1; 408cabdff1aSopenharmony_ci /* bit 1 of the flags: 0 = 8 bit, 1 = 16 bit */ 409cabdff1aSopenharmony_ci s->audio_bits = (((audio_flags >> 1) & 1) + 1) * 8; 410cabdff1aSopenharmony_ci /* bit 2 indicates compressed audio in version 1 opcode */ 411cabdff1aSopenharmony_ci if ((opcode_version == 1) && (audio_flags & 0x4)) 412cabdff1aSopenharmony_ci s->audio_type = AV_CODEC_ID_INTERPLAY_DPCM; 413cabdff1aSopenharmony_ci else if (s->audio_bits == 16) 414cabdff1aSopenharmony_ci s->audio_type = AV_CODEC_ID_PCM_S16LE; 415cabdff1aSopenharmony_ci else 416cabdff1aSopenharmony_ci s->audio_type = AV_CODEC_ID_PCM_U8; 417cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "audio: %d bits, %d Hz, %s, %s format\n", 418cabdff1aSopenharmony_ci s->audio_bits, s->audio_sample_rate, 419cabdff1aSopenharmony_ci (s->audio_channels == 2) ? "stereo" : "mono", 420cabdff1aSopenharmony_ci (s->audio_type == AV_CODEC_ID_INTERPLAY_DPCM) ? 421cabdff1aSopenharmony_ci "Interplay audio" : "PCM"); 422cabdff1aSopenharmony_ci break; 423cabdff1aSopenharmony_ci 424cabdff1aSopenharmony_ci case OPCODE_START_STOP_AUDIO: 425cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "start/stop audio\n"); 426cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 427cabdff1aSopenharmony_ci break; 428cabdff1aSopenharmony_ci 429cabdff1aSopenharmony_ci case OPCODE_INIT_VIDEO_BUFFERS: 430cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "initialize video buffers\n"); 431cabdff1aSopenharmony_ci if ((opcode_version > 2) || (opcode_size > 8) || opcode_size < 4 432cabdff1aSopenharmony_ci || opcode_version == 2 && opcode_size < 8 433cabdff1aSopenharmony_ci ) { 434cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "bad init_video_buffers opcode\n"); 435cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 436cabdff1aSopenharmony_ci break; 437cabdff1aSopenharmony_ci } 438cabdff1aSopenharmony_ci if (avio_read(pb, scratch, opcode_size) != 439cabdff1aSopenharmony_ci opcode_size) { 440cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 441cabdff1aSopenharmony_ci break; 442cabdff1aSopenharmony_ci } 443cabdff1aSopenharmony_ci width = AV_RL16(&scratch[0]) * 8; 444cabdff1aSopenharmony_ci height = AV_RL16(&scratch[2]) * 8; 445cabdff1aSopenharmony_ci if (width != s->video_width) { 446cabdff1aSopenharmony_ci s->video_width = width; 447cabdff1aSopenharmony_ci s->changed++; 448cabdff1aSopenharmony_ci } 449cabdff1aSopenharmony_ci if (height != s->video_height) { 450cabdff1aSopenharmony_ci s->video_height = height; 451cabdff1aSopenharmony_ci s->changed++; 452cabdff1aSopenharmony_ci } 453cabdff1aSopenharmony_ci if (opcode_version < 2 || !AV_RL16(&scratch[6])) { 454cabdff1aSopenharmony_ci s->video_bpp = 8; 455cabdff1aSopenharmony_ci } else { 456cabdff1aSopenharmony_ci s->video_bpp = 16; 457cabdff1aSopenharmony_ci } 458cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "video resolution: %d x %d\n", 459cabdff1aSopenharmony_ci s->video_width, s->video_height); 460cabdff1aSopenharmony_ci break; 461cabdff1aSopenharmony_ci 462cabdff1aSopenharmony_ci case OPCODE_UNKNOWN_12: 463cabdff1aSopenharmony_ci case OPCODE_UNKNOWN_13: 464cabdff1aSopenharmony_ci case OPCODE_UNKNOWN_14: 465cabdff1aSopenharmony_ci case OPCODE_UNKNOWN_15: 466cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "unknown (but documented) opcode %02X\n", opcode_type); 467cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 468cabdff1aSopenharmony_ci break; 469cabdff1aSopenharmony_ci 470cabdff1aSopenharmony_ci case OPCODE_SEND_BUFFER: 471cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "send buffer\n"); 472cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 473cabdff1aSopenharmony_ci s->send_buffer = 1; 474cabdff1aSopenharmony_ci break; 475cabdff1aSopenharmony_ci 476cabdff1aSopenharmony_ci case OPCODE_AUDIO_FRAME: 477cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "audio frame\n"); 478cabdff1aSopenharmony_ci 479cabdff1aSopenharmony_ci /* log position and move on for now */ 480cabdff1aSopenharmony_ci s->audio_chunk_offset = avio_tell(pb); 481cabdff1aSopenharmony_ci s->audio_chunk_size = opcode_size; 482cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 483cabdff1aSopenharmony_ci break; 484cabdff1aSopenharmony_ci 485cabdff1aSopenharmony_ci case OPCODE_SILENCE_FRAME: 486cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "silence frame\n"); 487cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 488cabdff1aSopenharmony_ci break; 489cabdff1aSopenharmony_ci 490cabdff1aSopenharmony_ci case OPCODE_INIT_VIDEO_MODE: 491cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "initialize video mode\n"); 492cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 493cabdff1aSopenharmony_ci break; 494cabdff1aSopenharmony_ci 495cabdff1aSopenharmony_ci case OPCODE_CREATE_GRADIENT: 496cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "create gradient\n"); 497cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 498cabdff1aSopenharmony_ci break; 499cabdff1aSopenharmony_ci 500cabdff1aSopenharmony_ci case OPCODE_SET_PALETTE: 501cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "set palette\n"); 502cabdff1aSopenharmony_ci /* check for the logical maximum palette size 503cabdff1aSopenharmony_ci * (3 * 256 + 4 bytes) */ 504cabdff1aSopenharmony_ci if (opcode_size > 0x304 || opcode_size < 4) { 505cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "demux_ipmovie: set_palette opcode with invalid size\n"); 506cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 507cabdff1aSopenharmony_ci break; 508cabdff1aSopenharmony_ci } 509cabdff1aSopenharmony_ci if (avio_read(pb, scratch, opcode_size) != opcode_size) { 510cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 511cabdff1aSopenharmony_ci break; 512cabdff1aSopenharmony_ci } 513cabdff1aSopenharmony_ci 514cabdff1aSopenharmony_ci /* load the palette into internal data structure */ 515cabdff1aSopenharmony_ci first_color = AV_RL16(&scratch[0]); 516cabdff1aSopenharmony_ci last_color = first_color + AV_RL16(&scratch[2]) - 1; 517cabdff1aSopenharmony_ci /* sanity check (since they are 16 bit values) */ 518cabdff1aSopenharmony_ci if ( (first_color > 0xFF) || (last_color > 0xFF) 519cabdff1aSopenharmony_ci || (last_color - first_color + 1)*3 + 4 > opcode_size) { 520cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "demux_ipmovie: set_palette indexes out of range (%d -> %d)\n", 521cabdff1aSopenharmony_ci first_color, last_color); 522cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 523cabdff1aSopenharmony_ci break; 524cabdff1aSopenharmony_ci } 525cabdff1aSopenharmony_ci j = 4; /* offset of first palette data */ 526cabdff1aSopenharmony_ci for (i = first_color; i <= last_color; i++) { 527cabdff1aSopenharmony_ci /* the palette is stored as a 6-bit VGA palette, thus each 528cabdff1aSopenharmony_ci * component is shifted up to a 8-bit range */ 529cabdff1aSopenharmony_ci r = scratch[j++] * 4; 530cabdff1aSopenharmony_ci g = scratch[j++] * 4; 531cabdff1aSopenharmony_ci b = scratch[j++] * 4; 532cabdff1aSopenharmony_ci s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | (b); 533cabdff1aSopenharmony_ci s->palette[i] |= s->palette[i] >> 6 & 0x30303; 534cabdff1aSopenharmony_ci } 535cabdff1aSopenharmony_ci s->has_palette = 1; 536cabdff1aSopenharmony_ci break; 537cabdff1aSopenharmony_ci 538cabdff1aSopenharmony_ci case OPCODE_SET_PALETTE_COMPRESSED: 539cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "set palette compressed\n"); 540cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 541cabdff1aSopenharmony_ci break; 542cabdff1aSopenharmony_ci 543cabdff1aSopenharmony_ci case OPCODE_SET_SKIP_MAP: 544cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "set skip map\n"); 545cabdff1aSopenharmony_ci 546cabdff1aSopenharmony_ci /* log position and move on for now */ 547cabdff1aSopenharmony_ci s->skip_map_chunk_offset = avio_tell(pb); 548cabdff1aSopenharmony_ci s->skip_map_chunk_size = opcode_size; 549cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 550cabdff1aSopenharmony_ci break; 551cabdff1aSopenharmony_ci 552cabdff1aSopenharmony_ci case OPCODE_SET_DECODING_MAP: 553cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "set decoding map\n"); 554cabdff1aSopenharmony_ci 555cabdff1aSopenharmony_ci /* log position and move on for now */ 556cabdff1aSopenharmony_ci s->decode_map_chunk_offset = avio_tell(pb); 557cabdff1aSopenharmony_ci s->decode_map_chunk_size = opcode_size; 558cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 559cabdff1aSopenharmony_ci break; 560cabdff1aSopenharmony_ci 561cabdff1aSopenharmony_ci case OPCODE_VIDEO_DATA_06: 562cabdff1aSopenharmony_ci case OPCODE_VIDEO_DATA_10: 563cabdff1aSopenharmony_ci case OPCODE_VIDEO_DATA_11: 564cabdff1aSopenharmony_ci s->frame_format = opcode_type; 565cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "set video data format 0x%02X\n", 566cabdff1aSopenharmony_ci opcode_type); 567cabdff1aSopenharmony_ci 568cabdff1aSopenharmony_ci /* log position and move on for now */ 569cabdff1aSopenharmony_ci s->video_chunk_offset = avio_tell(pb); 570cabdff1aSopenharmony_ci s->video_chunk_size = opcode_size; 571cabdff1aSopenharmony_ci avio_skip(pb, opcode_size); 572cabdff1aSopenharmony_ci break; 573cabdff1aSopenharmony_ci 574cabdff1aSopenharmony_ci default: 575cabdff1aSopenharmony_ci av_log(s->avf, AV_LOG_TRACE, "*** unknown opcode type\n"); 576cabdff1aSopenharmony_ci chunk_type = CHUNK_BAD; 577cabdff1aSopenharmony_ci break; 578cabdff1aSopenharmony_ci 579cabdff1aSopenharmony_ci } 580cabdff1aSopenharmony_ci } 581cabdff1aSopenharmony_ci 582cabdff1aSopenharmony_ci if (s->avf->nb_streams == 1 && s->audio_type) 583cabdff1aSopenharmony_ci init_audio(s->avf); 584cabdff1aSopenharmony_ci 585cabdff1aSopenharmony_ci /* make a note of where the stream is sitting */ 586cabdff1aSopenharmony_ci s->next_chunk_offset = avio_tell(pb); 587cabdff1aSopenharmony_ci 588cabdff1aSopenharmony_ci return chunk_type; 589cabdff1aSopenharmony_ci} 590cabdff1aSopenharmony_ci 591cabdff1aSopenharmony_cistatic const char signature[] = "Interplay MVE File\x1A\0\x1A"; 592cabdff1aSopenharmony_ci 593cabdff1aSopenharmony_cistatic int ipmovie_probe(const AVProbeData *p) 594cabdff1aSopenharmony_ci{ 595cabdff1aSopenharmony_ci const uint8_t *b = p->buf; 596cabdff1aSopenharmony_ci const uint8_t *b_end = p->buf + p->buf_size - sizeof(signature); 597cabdff1aSopenharmony_ci do { 598cabdff1aSopenharmony_ci if (b[0] == signature[0] && memcmp(b, signature, sizeof(signature)) == 0) 599cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 600cabdff1aSopenharmony_ci b++; 601cabdff1aSopenharmony_ci } while (b < b_end); 602cabdff1aSopenharmony_ci 603cabdff1aSopenharmony_ci return 0; 604cabdff1aSopenharmony_ci} 605cabdff1aSopenharmony_ci 606cabdff1aSopenharmony_cistatic int ipmovie_read_header(AVFormatContext *s) 607cabdff1aSopenharmony_ci{ 608cabdff1aSopenharmony_ci IPMVEContext *ipmovie = s->priv_data; 609cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 610cabdff1aSopenharmony_ci AVStream *st; 611cabdff1aSopenharmony_ci unsigned char chunk_preamble[CHUNK_PREAMBLE_SIZE]; 612cabdff1aSopenharmony_ci int chunk_type, i; 613cabdff1aSopenharmony_ci uint8_t signature_buffer[sizeof(signature)]; 614cabdff1aSopenharmony_ci 615cabdff1aSopenharmony_ci ipmovie->avf = s; 616cabdff1aSopenharmony_ci 617cabdff1aSopenharmony_ci avio_read(pb, signature_buffer, sizeof(signature_buffer)); 618cabdff1aSopenharmony_ci while (memcmp(signature_buffer, signature, sizeof(signature))) { 619cabdff1aSopenharmony_ci memmove(signature_buffer, signature_buffer + 1, sizeof(signature_buffer) - 1); 620cabdff1aSopenharmony_ci signature_buffer[sizeof(signature_buffer) - 1] = avio_r8(pb); 621cabdff1aSopenharmony_ci if (avio_feof(pb)) 622cabdff1aSopenharmony_ci return AVERROR_EOF; 623cabdff1aSopenharmony_ci } 624cabdff1aSopenharmony_ci 625cabdff1aSopenharmony_ci /* on the first read, this will position the stream at the first chunk */ 626cabdff1aSopenharmony_ci ipmovie->next_chunk_offset = avio_tell(pb) + 4; 627cabdff1aSopenharmony_ci 628cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) 629cabdff1aSopenharmony_ci ipmovie->palette[i] = 0xFFU << 24; 630cabdff1aSopenharmony_ci 631cabdff1aSopenharmony_ci /* process the first chunk which should be CHUNK_INIT_VIDEO */ 632cabdff1aSopenharmony_ci if (process_ipmovie_chunk(ipmovie, pb, NULL) != CHUNK_INIT_VIDEO) { 633cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 634cabdff1aSopenharmony_ci } 635cabdff1aSopenharmony_ci 636cabdff1aSopenharmony_ci /* peek ahead to the next chunk-- if it is an init audio chunk, process 637cabdff1aSopenharmony_ci * it; if it is the first video chunk, this is a silent file */ 638cabdff1aSopenharmony_ci if (avio_read(pb, chunk_preamble, CHUNK_PREAMBLE_SIZE) != 639cabdff1aSopenharmony_ci CHUNK_PREAMBLE_SIZE) 640cabdff1aSopenharmony_ci return AVERROR(EIO); 641cabdff1aSopenharmony_ci chunk_type = AV_RL16(&chunk_preamble[2]); 642cabdff1aSopenharmony_ci avio_seek(pb, -CHUNK_PREAMBLE_SIZE, SEEK_CUR); 643cabdff1aSopenharmony_ci 644cabdff1aSopenharmony_ci if (chunk_type == CHUNK_VIDEO) 645cabdff1aSopenharmony_ci ipmovie->audio_type = AV_CODEC_ID_NONE; /* no audio */ 646cabdff1aSopenharmony_ci else if (process_ipmovie_chunk(ipmovie, pb, ffformatcontext(s)->parse_pkt) != CHUNK_INIT_AUDIO) { 647cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 648cabdff1aSopenharmony_ci } 649cabdff1aSopenharmony_ci 650cabdff1aSopenharmony_ci /* initialize the stream decoders */ 651cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 652cabdff1aSopenharmony_ci if (!st) 653cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 654cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 63, 1, 1000000); 655cabdff1aSopenharmony_ci ipmovie->video_stream_index = st->index; 656cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 657cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_INTERPLAY_VIDEO; 658cabdff1aSopenharmony_ci st->codecpar->codec_tag = 0; /* no fourcc */ 659cabdff1aSopenharmony_ci st->codecpar->width = ipmovie->video_width; 660cabdff1aSopenharmony_ci st->codecpar->height = ipmovie->video_height; 661cabdff1aSopenharmony_ci st->codecpar->bits_per_coded_sample = ipmovie->video_bpp; 662cabdff1aSopenharmony_ci 663cabdff1aSopenharmony_ci if (ipmovie->audio_type) { 664cabdff1aSopenharmony_ci return init_audio(s); 665cabdff1aSopenharmony_ci } else 666cabdff1aSopenharmony_ci s->ctx_flags |= AVFMTCTX_NOHEADER; 667cabdff1aSopenharmony_ci 668cabdff1aSopenharmony_ci return 0; 669cabdff1aSopenharmony_ci} 670cabdff1aSopenharmony_ci 671cabdff1aSopenharmony_cistatic int ipmovie_read_packet(AVFormatContext *s, 672cabdff1aSopenharmony_ci AVPacket *pkt) 673cabdff1aSopenharmony_ci{ 674cabdff1aSopenharmony_ci IPMVEContext *ipmovie = s->priv_data; 675cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 676cabdff1aSopenharmony_ci int ret; 677cabdff1aSopenharmony_ci 678cabdff1aSopenharmony_ci for (;;) { 679cabdff1aSopenharmony_ci ret = process_ipmovie_chunk(ipmovie, pb, pkt); 680cabdff1aSopenharmony_ci /* dispatch the first of any pending packets */ 681cabdff1aSopenharmony_ci if ((ret == CHUNK_VIDEO) || (ret == CHUNK_AUDIO_ONLY)) 682cabdff1aSopenharmony_ci ret = load_ipmovie_packet(ipmovie, pb, pkt); 683cabdff1aSopenharmony_ci 684cabdff1aSopenharmony_ci if (ret == CHUNK_BAD) 685cabdff1aSopenharmony_ci ret = AVERROR_INVALIDDATA; 686cabdff1aSopenharmony_ci else if (ret == CHUNK_EOF) 687cabdff1aSopenharmony_ci ret = AVERROR(EIO); 688cabdff1aSopenharmony_ci else if (ret == CHUNK_NOMEM) 689cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 690cabdff1aSopenharmony_ci else if (ret == CHUNK_END || ret == CHUNK_SHUTDOWN) 691cabdff1aSopenharmony_ci ret = AVERROR_EOF; 692cabdff1aSopenharmony_ci else if (ret == CHUNK_HAVE_PACKET) 693cabdff1aSopenharmony_ci ret = 0; 694cabdff1aSopenharmony_ci else if (ret == CHUNK_INIT_VIDEO || ret == CHUNK_INIT_AUDIO) 695cabdff1aSopenharmony_ci continue; 696cabdff1aSopenharmony_ci else 697cabdff1aSopenharmony_ci continue; 698cabdff1aSopenharmony_ci 699cabdff1aSopenharmony_ci return ret; 700cabdff1aSopenharmony_ci } 701cabdff1aSopenharmony_ci} 702cabdff1aSopenharmony_ci 703cabdff1aSopenharmony_ciconst AVInputFormat ff_ipmovie_demuxer = { 704cabdff1aSopenharmony_ci .name = "ipmovie", 705cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE"), 706cabdff1aSopenharmony_ci .priv_data_size = sizeof(IPMVEContext), 707cabdff1aSopenharmony_ci .read_probe = ipmovie_probe, 708cabdff1aSopenharmony_ci .read_header = ipmovie_read_header, 709cabdff1aSopenharmony_ci .read_packet = ipmovie_read_packet, 710cabdff1aSopenharmony_ci}; 711