1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * VPK demuxer 3cabdff1aSopenharmony_ci * Copyright (c) 2015 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#include "avformat.h" 24cabdff1aSopenharmony_ci#include "demux.h" 25cabdff1aSopenharmony_ci#include "internal.h" 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_citypedef struct VPKDemuxContext { 28cabdff1aSopenharmony_ci unsigned data_start; 29cabdff1aSopenharmony_ci unsigned block_count; 30cabdff1aSopenharmony_ci unsigned current_block; 31cabdff1aSopenharmony_ci unsigned last_block_size; 32cabdff1aSopenharmony_ci} VPKDemuxContext; 33cabdff1aSopenharmony_ci 34cabdff1aSopenharmony_cistatic int vpk_probe(const AVProbeData *p) 35cabdff1aSopenharmony_ci{ 36cabdff1aSopenharmony_ci if (AV_RL32(p->buf) != MKBETAG('V','P','K',' ')) 37cabdff1aSopenharmony_ci return 0; 38cabdff1aSopenharmony_ci 39cabdff1aSopenharmony_ci return AVPROBE_SCORE_MAX / 3 * 2; 40cabdff1aSopenharmony_ci} 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_cistatic int vpk_read_header(AVFormatContext *s) 43cabdff1aSopenharmony_ci{ 44cabdff1aSopenharmony_ci VPKDemuxContext *vpk = s->priv_data; 45cabdff1aSopenharmony_ci unsigned offset; 46cabdff1aSopenharmony_ci unsigned samples_per_block; 47cabdff1aSopenharmony_ci AVStream *st; 48cabdff1aSopenharmony_ci 49cabdff1aSopenharmony_ci vpk->current_block = 0; 50cabdff1aSopenharmony_ci st = avformat_new_stream(s, NULL); 51cabdff1aSopenharmony_ci if (!st) 52cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci avio_skip(s->pb, 4); 55cabdff1aSopenharmony_ci st->duration = avio_rl32(s->pb) * 28 / 16; 56cabdff1aSopenharmony_ci offset = avio_rl32(s->pb); 57cabdff1aSopenharmony_ci st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; 58cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_ADPCM_PSX; 59cabdff1aSopenharmony_ci st->codecpar->block_align = avio_rl32(s->pb); 60cabdff1aSopenharmony_ci st->codecpar->sample_rate = avio_rl32(s->pb); 61cabdff1aSopenharmony_ci if (st->codecpar->sample_rate <= 0 || st->codecpar->block_align <= 0) 62cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 63cabdff1aSopenharmony_ci st->codecpar->ch_layout.nb_channels = avio_rl32(s->pb); 64cabdff1aSopenharmony_ci if (st->codecpar->ch_layout.nb_channels <= 0) 65cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 66cabdff1aSopenharmony_ci samples_per_block = ((st->codecpar->block_align / st->codecpar->ch_layout.nb_channels) * 28LL) / 16; 67cabdff1aSopenharmony_ci if (samples_per_block <= 0) 68cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 69cabdff1aSopenharmony_ci vpk->block_count = (st->duration + (samples_per_block - 1)) / samples_per_block; 70cabdff1aSopenharmony_ci vpk->last_block_size = (st->duration % samples_per_block) * 16 * st->codecpar->ch_layout.nb_channels / 28; 71cabdff1aSopenharmony_ci 72cabdff1aSopenharmony_ci if (offset < avio_tell(s->pb)) 73cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 74cabdff1aSopenharmony_ci avio_skip(s->pb, offset - avio_tell(s->pb)); 75cabdff1aSopenharmony_ci vpk->data_start = offset; 76cabdff1aSopenharmony_ci avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); 77cabdff1aSopenharmony_ci 78cabdff1aSopenharmony_ci return 0; 79cabdff1aSopenharmony_ci} 80cabdff1aSopenharmony_ci 81cabdff1aSopenharmony_cistatic int vpk_read_packet(AVFormatContext *s, AVPacket *pkt) 82cabdff1aSopenharmony_ci{ 83cabdff1aSopenharmony_ci AVCodecParameters *par = s->streams[0]->codecpar; 84cabdff1aSopenharmony_ci VPKDemuxContext *vpk = s->priv_data; 85cabdff1aSopenharmony_ci int ret, i; 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_ci vpk->current_block++; 88cabdff1aSopenharmony_ci if (vpk->current_block == vpk->block_count) { 89cabdff1aSopenharmony_ci unsigned size = vpk->last_block_size / par->ch_layout.nb_channels; 90cabdff1aSopenharmony_ci unsigned skip = (par->block_align - vpk->last_block_size) / par->ch_layout.nb_channels; 91cabdff1aSopenharmony_ci uint64_t pos = avio_tell(s->pb); 92cabdff1aSopenharmony_ci 93cabdff1aSopenharmony_ci ret = av_new_packet(pkt, vpk->last_block_size); 94cabdff1aSopenharmony_ci if (ret < 0) 95cabdff1aSopenharmony_ci return ret; 96cabdff1aSopenharmony_ci for (i = 0; i < par->ch_layout.nb_channels; i++) { 97cabdff1aSopenharmony_ci ret = avio_read(s->pb, pkt->data + i * size, size); 98cabdff1aSopenharmony_ci avio_skip(s->pb, skip); 99cabdff1aSopenharmony_ci if (ret != size) { 100cabdff1aSopenharmony_ci return AVERROR(EIO); 101cabdff1aSopenharmony_ci } 102cabdff1aSopenharmony_ci } 103cabdff1aSopenharmony_ci pkt->pos = pos; 104cabdff1aSopenharmony_ci pkt->stream_index = 0; 105cabdff1aSopenharmony_ci } else if (vpk->current_block < vpk->block_count) { 106cabdff1aSopenharmony_ci ret = av_get_packet(s->pb, pkt, par->block_align); 107cabdff1aSopenharmony_ci pkt->stream_index = 0; 108cabdff1aSopenharmony_ci } else { 109cabdff1aSopenharmony_ci return AVERROR_EOF; 110cabdff1aSopenharmony_ci } 111cabdff1aSopenharmony_ci 112cabdff1aSopenharmony_ci return ret; 113cabdff1aSopenharmony_ci} 114cabdff1aSopenharmony_ci 115cabdff1aSopenharmony_cistatic int vpk_read_seek(AVFormatContext *s, int stream_index, 116cabdff1aSopenharmony_ci int64_t timestamp, int flags) 117cabdff1aSopenharmony_ci{ 118cabdff1aSopenharmony_ci AVStream *st = s->streams[stream_index]; 119cabdff1aSopenharmony_ci AVCodecParameters *par = st->codecpar; 120cabdff1aSopenharmony_ci VPKDemuxContext *vpk = s->priv_data; 121cabdff1aSopenharmony_ci int samples_per_block; 122cabdff1aSopenharmony_ci int64_t ret = 0; 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci samples_per_block = av_get_audio_frame_duration2(par, par->block_align); 125cabdff1aSopenharmony_ci if (samples_per_block > 0) 126cabdff1aSopenharmony_ci timestamp /= samples_per_block; 127cabdff1aSopenharmony_ci else 128cabdff1aSopenharmony_ci return -1; 129cabdff1aSopenharmony_ci ret = avio_seek(s->pb, vpk->data_start + timestamp * par->block_align, SEEK_SET); 130cabdff1aSopenharmony_ci if (ret < 0) 131cabdff1aSopenharmony_ci return ret; 132cabdff1aSopenharmony_ci 133cabdff1aSopenharmony_ci vpk->current_block = timestamp; 134cabdff1aSopenharmony_ci avpriv_update_cur_dts(s, st, timestamp * samples_per_block); 135cabdff1aSopenharmony_ci return 0; 136cabdff1aSopenharmony_ci} 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_ciconst AVInputFormat ff_vpk_demuxer = { 139cabdff1aSopenharmony_ci .name = "vpk", 140cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("Sony PS2 VPK"), 141cabdff1aSopenharmony_ci .priv_data_size = sizeof(VPKDemuxContext), 142cabdff1aSopenharmony_ci .read_probe = vpk_probe, 143cabdff1aSopenharmony_ci .read_header = vpk_read_header, 144cabdff1aSopenharmony_ci .read_packet = vpk_read_packet, 145cabdff1aSopenharmony_ci .read_seek = vpk_read_seek, 146cabdff1aSopenharmony_ci .extensions = "vpk", 147cabdff1aSopenharmony_ci}; 148