1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Psygnosis YOP demuxer 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * Copyright (C) 2010 Mohamed Naufal Basheer <naufal11@gmail.com> 5cabdff1aSopenharmony_ci * derived from the code by 6cabdff1aSopenharmony_ci * Copyright (C) 2009 Thomas P. Higdon <thomas.p.higdon@gmail.com> 7cabdff1aSopenharmony_ci * 8cabdff1aSopenharmony_ci * This file is part of FFmpeg. 9cabdff1aSopenharmony_ci * 10cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 11cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 12cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 13cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 14cabdff1aSopenharmony_ci * 15cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 16cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 17cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18cabdff1aSopenharmony_ci * Lesser General Public License for more details. 19cabdff1aSopenharmony_ci * 20cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 21cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 22cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23cabdff1aSopenharmony_ci */ 24cabdff1aSopenharmony_ci 25cabdff1aSopenharmony_ci#include "libavutil/channel_layout.h" 26cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h" 27cabdff1aSopenharmony_ci#include "avformat.h" 28cabdff1aSopenharmony_ci#include "demux.h" 29cabdff1aSopenharmony_ci#include "internal.h" 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_citypedef struct yop_dec_context { 32cabdff1aSopenharmony_ci AVPacket video_packet; 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_ci int odd_frame; 35cabdff1aSopenharmony_ci int frame_size; 36cabdff1aSopenharmony_ci int audio_block_length; 37cabdff1aSopenharmony_ci int palette_size; 38cabdff1aSopenharmony_ci} YopDecContext; 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_cistatic int yop_probe(const AVProbeData *probe_packet) 41cabdff1aSopenharmony_ci{ 42cabdff1aSopenharmony_ci if (AV_RB16(probe_packet->buf) == AV_RB16("YO") && 43cabdff1aSopenharmony_ci probe_packet->buf[2]<10 && 44cabdff1aSopenharmony_ci probe_packet->buf[3]<10 && 45cabdff1aSopenharmony_ci probe_packet->buf[6] && 46cabdff1aSopenharmony_ci probe_packet->buf[7] && 47cabdff1aSopenharmony_ci !(probe_packet->buf[8] & 1) && 48cabdff1aSopenharmony_ci !(probe_packet->buf[10] & 1) && 49cabdff1aSopenharmony_ci AV_RL16(probe_packet->buf + 12 + 6) >= 920 && 50cabdff1aSopenharmony_ci AV_RL16(probe_packet->buf + 12 + 6) < probe_packet->buf[12] * 3 + 4 + probe_packet->buf[7] * 2048 51cabdff1aSopenharmony_ci ) 52cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX * 3 / 4; 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci return 0; 55cabdff1aSopenharmony_ci} 56cabdff1aSopenharmony_ci 57cabdff1aSopenharmony_cistatic int yop_read_header(AVFormatContext *s) 58cabdff1aSopenharmony_ci{ 59cabdff1aSopenharmony_ci YopDecContext *yop = s->priv_data; 60cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 61cabdff1aSopenharmony_ci 62cabdff1aSopenharmony_ci AVCodecParameters *audio_par, *video_par; 63cabdff1aSopenharmony_ci AVStream *audio_stream, *video_stream; 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_ci int frame_rate, ret; 66cabdff1aSopenharmony_ci 67cabdff1aSopenharmony_ci audio_stream = avformat_new_stream(s, NULL); 68cabdff1aSopenharmony_ci video_stream = avformat_new_stream(s, NULL); 69cabdff1aSopenharmony_ci if (!audio_stream || !video_stream) 70cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci // Audio 73cabdff1aSopenharmony_ci audio_par = audio_stream->codecpar; 74cabdff1aSopenharmony_ci audio_par->codec_type = AVMEDIA_TYPE_AUDIO; 75cabdff1aSopenharmony_ci audio_par->codec_id = AV_CODEC_ID_ADPCM_IMA_APC; 76cabdff1aSopenharmony_ci audio_par->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO; 77cabdff1aSopenharmony_ci audio_par->sample_rate = 22050; 78cabdff1aSopenharmony_ci 79cabdff1aSopenharmony_ci // Video 80cabdff1aSopenharmony_ci video_par = video_stream->codecpar; 81cabdff1aSopenharmony_ci video_par->codec_type = AVMEDIA_TYPE_VIDEO; 82cabdff1aSopenharmony_ci video_par->codec_id = AV_CODEC_ID_YOP; 83cabdff1aSopenharmony_ci 84cabdff1aSopenharmony_ci avio_skip(pb, 6); 85cabdff1aSopenharmony_ci 86cabdff1aSopenharmony_ci frame_rate = avio_r8(pb); 87cabdff1aSopenharmony_ci yop->frame_size = avio_r8(pb) * 2048; 88cabdff1aSopenharmony_ci video_par->width = avio_rl16(pb); 89cabdff1aSopenharmony_ci video_par->height = avio_rl16(pb); 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci video_stream->sample_aspect_ratio = (AVRational){1, 2}; 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci ret = ff_get_extradata(s, video_par, pb, 8); 94cabdff1aSopenharmony_ci if (ret < 0) 95cabdff1aSopenharmony_ci return ret; 96cabdff1aSopenharmony_ci 97cabdff1aSopenharmony_ci yop->palette_size = video_par->extradata[0] * 3 + 4; 98cabdff1aSopenharmony_ci yop->audio_block_length = AV_RL16(video_par->extradata + 6); 99cabdff1aSopenharmony_ci 100cabdff1aSopenharmony_ci video_par->bit_rate = 8 * (yop->frame_size - yop->audio_block_length) * frame_rate; 101cabdff1aSopenharmony_ci 102cabdff1aSopenharmony_ci // 1840 samples per frame, 1 nibble per sample; hence 1840/2 = 920 103cabdff1aSopenharmony_ci if (yop->audio_block_length < 920 || 104cabdff1aSopenharmony_ci yop->audio_block_length + yop->palette_size >= yop->frame_size) { 105cabdff1aSopenharmony_ci av_log(s, AV_LOG_ERROR, "YOP has invalid header\n"); 106cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 107cabdff1aSopenharmony_ci } 108cabdff1aSopenharmony_ci 109cabdff1aSopenharmony_ci avio_seek(pb, 2048, SEEK_SET); 110cabdff1aSopenharmony_ci 111cabdff1aSopenharmony_ci avpriv_set_pts_info(video_stream, 32, 1, frame_rate); 112cabdff1aSopenharmony_ci 113cabdff1aSopenharmony_ci return 0; 114cabdff1aSopenharmony_ci} 115cabdff1aSopenharmony_ci 116cabdff1aSopenharmony_cistatic int yop_read_packet(AVFormatContext *s, AVPacket *pkt) 117cabdff1aSopenharmony_ci{ 118cabdff1aSopenharmony_ci YopDecContext *yop = s->priv_data; 119cabdff1aSopenharmony_ci AVIOContext *pb = s->pb; 120cabdff1aSopenharmony_ci 121cabdff1aSopenharmony_ci int ret; 122cabdff1aSopenharmony_ci int actual_video_data_size = yop->frame_size - 123cabdff1aSopenharmony_ci yop->audio_block_length - yop->palette_size; 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci yop->video_packet.stream_index = 1; 126cabdff1aSopenharmony_ci 127cabdff1aSopenharmony_ci if (yop->video_packet.data) { 128cabdff1aSopenharmony_ci av_packet_move_ref(pkt, &yop->video_packet); 129cabdff1aSopenharmony_ci pkt->data[0] = yop->odd_frame; 130cabdff1aSopenharmony_ci pkt->flags |= AV_PKT_FLAG_KEY; 131cabdff1aSopenharmony_ci yop->odd_frame ^= 1; 132cabdff1aSopenharmony_ci return 0; 133cabdff1aSopenharmony_ci } 134cabdff1aSopenharmony_ci ret = av_new_packet(&yop->video_packet, 135cabdff1aSopenharmony_ci yop->frame_size - yop->audio_block_length); 136cabdff1aSopenharmony_ci if (ret < 0) 137cabdff1aSopenharmony_ci return ret; 138cabdff1aSopenharmony_ci 139cabdff1aSopenharmony_ci yop->video_packet.pos = avio_tell(pb); 140cabdff1aSopenharmony_ci 141cabdff1aSopenharmony_ci ret = avio_read(pb, yop->video_packet.data, yop->palette_size); 142cabdff1aSopenharmony_ci if (ret < 0) { 143cabdff1aSopenharmony_ci goto err_out; 144cabdff1aSopenharmony_ci }else if (ret < yop->palette_size) { 145cabdff1aSopenharmony_ci ret = AVERROR_EOF; 146cabdff1aSopenharmony_ci goto err_out; 147cabdff1aSopenharmony_ci } 148cabdff1aSopenharmony_ci 149cabdff1aSopenharmony_ci ret = av_get_packet(pb, pkt, 920); 150cabdff1aSopenharmony_ci if (ret < 0) 151cabdff1aSopenharmony_ci goto err_out; 152cabdff1aSopenharmony_ci 153cabdff1aSopenharmony_ci // Set position to the start of the frame 154cabdff1aSopenharmony_ci pkt->pos = yop->video_packet.pos; 155cabdff1aSopenharmony_ci 156cabdff1aSopenharmony_ci avio_skip(pb, yop->audio_block_length - ret); 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_ci ret = avio_read(pb, yop->video_packet.data + yop->palette_size, 159cabdff1aSopenharmony_ci actual_video_data_size); 160cabdff1aSopenharmony_ci if (ret < 0) 161cabdff1aSopenharmony_ci goto err_out; 162cabdff1aSopenharmony_ci else if (ret < actual_video_data_size) 163cabdff1aSopenharmony_ci av_shrink_packet(&yop->video_packet, yop->palette_size + ret); 164cabdff1aSopenharmony_ci 165cabdff1aSopenharmony_ci // Arbitrarily return the audio data first 166cabdff1aSopenharmony_ci return 0; 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_cierr_out: 169cabdff1aSopenharmony_ci av_packet_unref(&yop->video_packet); 170cabdff1aSopenharmony_ci return ret; 171cabdff1aSopenharmony_ci} 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_cistatic int yop_read_close(AVFormatContext *s) 174cabdff1aSopenharmony_ci{ 175cabdff1aSopenharmony_ci YopDecContext *yop = s->priv_data; 176cabdff1aSopenharmony_ci av_packet_unref(&yop->video_packet); 177cabdff1aSopenharmony_ci return 0; 178cabdff1aSopenharmony_ci} 179cabdff1aSopenharmony_ci 180cabdff1aSopenharmony_cistatic int yop_read_seek(AVFormatContext *s, int stream_index, 181cabdff1aSopenharmony_ci int64_t timestamp, int flags) 182cabdff1aSopenharmony_ci{ 183cabdff1aSopenharmony_ci YopDecContext *yop = s->priv_data; 184cabdff1aSopenharmony_ci int64_t frame_pos, pos_min, pos_max; 185cabdff1aSopenharmony_ci int frame_count; 186cabdff1aSopenharmony_ci 187cabdff1aSopenharmony_ci if (!stream_index) 188cabdff1aSopenharmony_ci return -1; 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ci pos_min = ffformatcontext(s)->data_offset; 191cabdff1aSopenharmony_ci pos_max = avio_size(s->pb) - yop->frame_size; 192cabdff1aSopenharmony_ci frame_count = (pos_max - pos_min) / yop->frame_size; 193cabdff1aSopenharmony_ci 194cabdff1aSopenharmony_ci timestamp = FFMAX(0, FFMIN(frame_count, timestamp)); 195cabdff1aSopenharmony_ci 196cabdff1aSopenharmony_ci frame_pos = timestamp * yop->frame_size + pos_min; 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci if (avio_seek(s->pb, frame_pos, SEEK_SET) < 0) 199cabdff1aSopenharmony_ci return -1; 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_ci av_packet_unref(&yop->video_packet); 202cabdff1aSopenharmony_ci yop->odd_frame = timestamp & 1; 203cabdff1aSopenharmony_ci 204cabdff1aSopenharmony_ci return 0; 205cabdff1aSopenharmony_ci} 206cabdff1aSopenharmony_ci 207cabdff1aSopenharmony_ciconst AVInputFormat ff_yop_demuxer = { 208cabdff1aSopenharmony_ci .name = "yop", 209cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Psygnosis YOP"), 210cabdff1aSopenharmony_ci .priv_data_size = sizeof(YopDecContext), 211cabdff1aSopenharmony_ci .read_probe = yop_probe, 212cabdff1aSopenharmony_ci .read_header = yop_read_header, 213cabdff1aSopenharmony_ci .read_packet = yop_read_packet, 214cabdff1aSopenharmony_ci .read_close = yop_read_close, 215cabdff1aSopenharmony_ci .read_seek = yop_read_seek, 216cabdff1aSopenharmony_ci .extensions = "yop", 217cabdff1aSopenharmony_ci .flags = AVFMT_GENERIC_INDEX, 218cabdff1aSopenharmony_ci}; 219