1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Gremlin Digital Video demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2017 Paul B Mahol 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#include "libavutil/intreadwrite.h" 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci#include "avformat.h" 25cabdff1aSopenharmony_ci#include "avio.h" 26cabdff1aSopenharmony_ci#include "internal.h" 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_citypedef struct GDVContext { 29cabdff1aSopenharmony_ci int is_first_video; 30cabdff1aSopenharmony_ci int is_audio; 31cabdff1aSopenharmony_ci int audio_size; 32cabdff1aSopenharmony_ci int audio_stream_index; 33cabdff1aSopenharmony_ci int video_stream_index; 34cabdff1aSopenharmony_ci unsigned pal[256]; 35cabdff1aSopenharmony_ci} GDVContext; 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_cistatic int gdv_read_probe(const AVProbeData *p) 38cabdff1aSopenharmony_ci{ 39cabdff1aSopenharmony_ci if (AV_RL32(p->buf) == 0x29111994) 40cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX; 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_ci return 0; 43cabdff1aSopenharmony_ci} 44cabdff1aSopenharmony_ci 45cabdff1aSopenharmony_cistatic struct { 46cabdff1aSopenharmony_ci uint16_t id; 47cabdff1aSopenharmony_ci uint16_t width; 48cabdff1aSopenharmony_ci uint16_t height; 49cabdff1aSopenharmony_ci} FixedSize[] = { 50cabdff1aSopenharmony_ci { 0, 320, 200}, 51cabdff1aSopenharmony_ci { 1, 640, 200}, 52cabdff1aSopenharmony_ci { 2, 320, 167}, 53cabdff1aSopenharmony_ci { 3, 320, 180}, 54cabdff1aSopenharmony_ci { 4, 320, 400}, 55cabdff1aSopenharmony_ci { 5, 320, 170}, 56cabdff1aSopenharmony_ci { 6, 160, 85}, 57cabdff1aSopenharmony_ci { 7, 160, 83}, 58cabdff1aSopenharmony_ci { 8, 160, 90}, 59cabdff1aSopenharmony_ci { 9, 280, 128}, 60cabdff1aSopenharmony_ci {10, 320, 240}, 61cabdff1aSopenharmony_ci {11, 320, 201}, 62cabdff1aSopenharmony_ci {16, 640, 400}, 63cabdff1aSopenharmony_ci {17, 640, 200}, 64cabdff1aSopenharmony_ci {18, 640, 180}, 65cabdff1aSopenharmony_ci {19, 640, 167}, 66cabdff1aSopenharmony_ci {20, 640, 170}, 67cabdff1aSopenharmony_ci {21, 320, 240} 68cabdff1aSopenharmony_ci}; 69cabdff1aSopenharmony_ci 70cabdff1aSopenharmony_cistatic int gdv_read_header(AVFormatContext *ctx) 71cabdff1aSopenharmony_ci{ 72cabdff1aSopenharmony_ci GDVContext *gdv = ctx->priv_data; 73cabdff1aSopenharmony_ci AVIOContext *pb = ctx->pb; 74cabdff1aSopenharmony_ci AVStream *vst, *ast; 75cabdff1aSopenharmony_ci unsigned fps, snd_flags, vid_depth, size_id; 76cabdff1aSopenharmony_ci 77cabdff1aSopenharmony_ci avio_skip(pb, 4); 78cabdff1aSopenharmony_ci size_id = avio_rl16(pb); 79cabdff1aSopenharmony_ci 80cabdff1aSopenharmony_ci vst = avformat_new_stream(ctx, 0); 81cabdff1aSopenharmony_ci if (!vst) 82cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci vst->start_time = 0; 85cabdff1aSopenharmony_ci vst->duration = 86cabdff1aSopenharmony_ci vst->nb_frames = avio_rl16(pb); 87cabdff1aSopenharmony_ci 88cabdff1aSopenharmony_ci fps = avio_rl16(pb); 89cabdff1aSopenharmony_ci if (!fps) 90cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 91cabdff1aSopenharmony_ci 92cabdff1aSopenharmony_ci snd_flags = avio_rl16(pb); 93cabdff1aSopenharmony_ci if (snd_flags & 1) { 94cabdff1aSopenharmony_ci ast = avformat_new_stream(ctx, 0); 95cabdff1aSopenharmony_ci if (!ast) 96cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 97cabdff1aSopenharmony_ci 98cabdff1aSopenharmony_ci ast->start_time = 0; 99cabdff1aSopenharmony_ci ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 100cabdff1aSopenharmony_ci ast->codecpar->codec_tag = 0; 101cabdff1aSopenharmony_ci ast->codecpar->sample_rate = avio_rl16(pb); 102cabdff1aSopenharmony_ci ast->codecpar->ch_layout.nb_channels = 1 + !!(snd_flags & 2); 103cabdff1aSopenharmony_ci if (snd_flags & 8) { 104cabdff1aSopenharmony_ci ast->codecpar->codec_id = AV_CODEC_ID_GREMLIN_DPCM; 105cabdff1aSopenharmony_ci } else { 106cabdff1aSopenharmony_ci ast->codecpar->codec_id = (snd_flags & 4) ? AV_CODEC_ID_PCM_S16LE : AV_CODEC_ID_PCM_U8; 107cabdff1aSopenharmony_ci } 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci avpriv_set_pts_info(ast, 64, 1, ast->codecpar->sample_rate); 110cabdff1aSopenharmony_ci gdv->audio_size = (ast->codecpar->sample_rate / fps) * 111cabdff1aSopenharmony_ci ast->codecpar->ch_layout.nb_channels * 112cabdff1aSopenharmony_ci (1 + !!(snd_flags & 4)) / (1 + !!(snd_flags & 8)); 113cabdff1aSopenharmony_ci gdv->is_audio = 1; 114cabdff1aSopenharmony_ci } else { 115cabdff1aSopenharmony_ci avio_skip(pb, 2); 116cabdff1aSopenharmony_ci } 117cabdff1aSopenharmony_ci vid_depth = avio_rl16(pb); 118cabdff1aSopenharmony_ci avio_skip(pb, 4); 119cabdff1aSopenharmony_ci 120cabdff1aSopenharmony_ci vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; 121cabdff1aSopenharmony_ci vst->codecpar->codec_id = AV_CODEC_ID_GDV; 122cabdff1aSopenharmony_ci vst->codecpar->codec_tag = 0; 123cabdff1aSopenharmony_ci vst->codecpar->width = avio_rl16(pb); 124cabdff1aSopenharmony_ci vst->codecpar->height = avio_rl16(pb); 125cabdff1aSopenharmony_ci 126cabdff1aSopenharmony_ci if (vst->codecpar->width == 0 || vst->codecpar->height == 0) { 127cabdff1aSopenharmony_ci int i; 128cabdff1aSopenharmony_ci 129cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(FixedSize) - 1; i++) { 130cabdff1aSopenharmony_ci if (FixedSize[i].id == size_id) 131cabdff1aSopenharmony_ci break; 132cabdff1aSopenharmony_ci } 133cabdff1aSopenharmony_ci 134cabdff1aSopenharmony_ci vst->codecpar->width = FixedSize[i].width; 135cabdff1aSopenharmony_ci vst->codecpar->height = FixedSize[i].height; 136cabdff1aSopenharmony_ci } 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ci avpriv_set_pts_info(vst, 64, 1, fps); 139cabdff1aSopenharmony_ci 140cabdff1aSopenharmony_ci if (vid_depth & 1) { 141cabdff1aSopenharmony_ci int i; 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_ci for (i = 0; i < 256; i++) { 144cabdff1aSopenharmony_ci unsigned r = avio_r8(pb); 145cabdff1aSopenharmony_ci unsigned g = avio_r8(pb); 146cabdff1aSopenharmony_ci unsigned b = avio_r8(pb); 147cabdff1aSopenharmony_ci gdv->pal[i] = 0xFFU << 24 | r << 18 | g << 10 | b << 2; 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci } 150cabdff1aSopenharmony_ci 151cabdff1aSopenharmony_ci gdv->is_first_video = 1; 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci return 0; 154cabdff1aSopenharmony_ci} 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_cistatic int gdv_read_packet(AVFormatContext *ctx, AVPacket *pkt) 157cabdff1aSopenharmony_ci{ 158cabdff1aSopenharmony_ci GDVContext *gdv = ctx->priv_data; 159cabdff1aSopenharmony_ci AVIOContext *pb = ctx->pb; 160cabdff1aSopenharmony_ci int ret; 161cabdff1aSopenharmony_ci 162cabdff1aSopenharmony_ci if (avio_feof(pb)) 163cabdff1aSopenharmony_ci return pb->error ? pb->error : AVERROR_EOF; 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci if (gdv->audio_size && gdv->is_audio) { 166cabdff1aSopenharmony_ci ret = av_get_packet(pb, pkt, gdv->audio_size); 167cabdff1aSopenharmony_ci if (ret < 0) 168cabdff1aSopenharmony_ci return ret; 169cabdff1aSopenharmony_ci pkt->stream_index = 1; 170cabdff1aSopenharmony_ci gdv->is_audio = 0; 171cabdff1aSopenharmony_ci } else { 172cabdff1aSopenharmony_ci uint8_t *pal; 173cabdff1aSopenharmony_ci 174cabdff1aSopenharmony_ci if (avio_rl16(pb) != 0x1305) 175cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 176cabdff1aSopenharmony_ci ret = av_get_packet(pb, pkt, 4 + avio_rl16(pb)); 177cabdff1aSopenharmony_ci if (ret < 0) 178cabdff1aSopenharmony_ci return ret; 179cabdff1aSopenharmony_ci pkt->stream_index = 0; 180cabdff1aSopenharmony_ci gdv->is_audio = 1; 181cabdff1aSopenharmony_ci 182cabdff1aSopenharmony_ci if (gdv->is_first_video) { 183cabdff1aSopenharmony_ci pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, 184cabdff1aSopenharmony_ci AVPALETTE_SIZE); 185cabdff1aSopenharmony_ci if (!pal) { 186cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 187cabdff1aSopenharmony_ci } 188cabdff1aSopenharmony_ci memcpy(pal, gdv->pal, AVPALETTE_SIZE); 189cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 190cabdff1aSopenharmony_ci gdv->is_first_video = 0; 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci } 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ci return 0; 195cabdff1aSopenharmony_ci} 196cabdff1aSopenharmony_ci 197cabdff1aSopenharmony_ciconst AVInputFormat ff_gdv_demuxer = { 198cabdff1aSopenharmony_ci .name = "gdv", 199cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Gremlin Digital Video"), 200cabdff1aSopenharmony_ci .priv_data_size = sizeof(GDVContext), 201cabdff1aSopenharmony_ci .read_probe = gdv_read_probe, 202cabdff1aSopenharmony_ci .read_header = gdv_read_header, 203cabdff1aSopenharmony_ci .read_packet = gdv_read_packet, 204cabdff1aSopenharmony_ci}; 205