argo_cvg.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. * Argonaut Games CVG demuxer
  3. *
  4. * Copyright (C) 2021 Zane van Iperen (zane@zanevaniperen.com)
  5. *
  6. * This file is part of FFmpeg.
  7. *
  8. * FFmpeg is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2.1 of the License, or (at your option) any later version.
  12. *
  13. * FFmpeg is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with FFmpeg; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. */
  22. #include "avformat.h"
  23. #include "internal.h"
  24. #include "libavutil/intreadwrite.h"
  25. /*
  26. * .CVG files are essentially PSX ADPCM wrapped with a size and checksum.
  27. * Found in the PSX versions of the game.
  28. */
  29. #define ARGO_CVG_HEADER_SIZE 12
  30. #define ARGO_CVG_BLOCK_ALIGN 0x10
  31. #define ARGO_CVG_NB_BLOCKS 32
  32. #define ARGO_CVG_SAMPLES_PER_BLOCK 28
  33. typedef struct ArgoCVGHeader {
  34. uint32_t size; /*< File size -8 (this + trailing checksum) */
  35. uint32_t unk1; /*< Unknown. Always seems to be 0 or 1. */
  36. uint32_t unk2; /*< Unknown. Always seems to be 0 or 1. */
  37. } ArgoCVGHeader;
  38. typedef struct ArgoCVGOverride {
  39. const char *name;
  40. ArgoCVGHeader header;
  41. uint32_t checksum;
  42. int sample_rate;
  43. } ArgoCVGOverride;
  44. typedef struct ArgoCVGDemuxContext {
  45. ArgoCVGHeader header;
  46. uint32_t checksum;
  47. uint32_t num_blocks;
  48. uint32_t blocks_read;
  49. } ArgoCVGDemuxContext;
  50. /* "Special" files that are played at a different rate. */
  51. static ArgoCVGOverride overrides[] = {
  52. { "CRYS.CVG", { 23592, 0, 1 }, 2495499, 88200 }, /* Beta */
  53. { "REDCRY88.CVG", { 38280, 0, 1 }, 4134848, 88200 }, /* Beta */
  54. { "DANLOOP1.CVG", { 54744, 1, 0 }, 5684641, 37800 }, /* Beta */
  55. { "PICKUP88.CVG", { 12904, 0, 1 }, 1348091, 48000 }, /* Beta */
  56. { "SELECT1.CVG", { 5080, 0, 1 }, 549987, 44100 }, /* Beta */
  57. };
  58. static int argo_cvg_probe(const AVProbeData *p)
  59. {
  60. ArgoCVGHeader cvg;
  61. /*
  62. * It's almost impossible to detect these files based
  63. * on the header alone. File extension is (unfortunately)
  64. * the best way forward.
  65. */
  66. if (!av_match_ext(p->filename, "cvg"))
  67. return 0;
  68. if (p->buf_size < ARGO_CVG_HEADER_SIZE)
  69. return 0;
  70. cvg.size = AV_RL32(p->buf + 0);
  71. cvg.unk1 = AV_RL32(p->buf + 4);
  72. cvg.unk2 = AV_RL32(p->buf + 8);
  73. if (cvg.size < 8)
  74. return 0;
  75. if (cvg.unk1 != 0 && cvg.unk1 != 1)
  76. return 0;
  77. if (cvg.unk2 != 0 && cvg.unk2 != 1)
  78. return 0;
  79. return AVPROBE_SCORE_MAX / 4 + 1;
  80. }
  81. static int argo_cvg_read_checksum(AVIOContext *pb, const ArgoCVGHeader *cvg, uint32_t *checksum)
  82. {
  83. int ret;
  84. uint8_t buf[4];
  85. if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) {
  86. *checksum = 0;
  87. return 0;
  88. }
  89. if ((ret = avio_seek(pb, cvg->size + 4, SEEK_SET)) < 0)
  90. return ret;
  91. /* NB: Not using avio_rl32() because no error checking. */
  92. if ((ret = avio_read(pb, buf, sizeof(buf))) < 0)
  93. return ret;
  94. else if (ret != sizeof(buf))
  95. return AVERROR(EIO);
  96. if ((ret = avio_seek(pb, ARGO_CVG_HEADER_SIZE, SEEK_SET)) < 0)
  97. return ret;
  98. *checksum = AV_RL32(buf);
  99. return 0;
  100. }
  101. static int argo_cvg_read_header(AVFormatContext *s)
  102. {
  103. int ret;
  104. AVStream *st;
  105. AVCodecParameters *par;
  106. uint8_t buf[ARGO_CVG_HEADER_SIZE];
  107. const char *filename = av_basename(s->url);
  108. ArgoCVGDemuxContext *ctx = s->priv_data;
  109. if (!(st = avformat_new_stream(s, NULL)))
  110. return AVERROR(ENOMEM);
  111. if ((ret = avio_read(s->pb, buf, ARGO_CVG_HEADER_SIZE)) < 0)
  112. return ret;
  113. else if (ret != ARGO_CVG_HEADER_SIZE)
  114. return AVERROR(EIO);
  115. ctx->header.size = AV_RL32(buf + 0);
  116. ctx->header.unk1 = AV_RL32(buf + 4);
  117. ctx->header.unk2 = AV_RL32(buf + 8);
  118. if (ctx->header.size < 8)
  119. return AVERROR_INVALIDDATA;
  120. av_log(s, AV_LOG_TRACE, "size = %u\n", ctx->header.size);
  121. av_log(s, AV_LOG_TRACE, "unk = %u, %u\n", ctx->header.unk1, ctx->header.unk2);
  122. if ((ret = argo_cvg_read_checksum(s->pb, &ctx->header, &ctx->checksum)) < 0)
  123. return ret;
  124. av_log(s, AV_LOG_TRACE, "checksum = %u\n", ctx->checksum);
  125. par = st->codecpar;
  126. par->codec_type = AVMEDIA_TYPE_AUDIO;
  127. par->codec_id = AV_CODEC_ID_ADPCM_PSX;
  128. par->sample_rate = 22050;
  129. for (size_t i = 0; i < FF_ARRAY_ELEMS(overrides); i++) {
  130. const ArgoCVGOverride *ovr = overrides + i;
  131. if (ovr->header.size != ctx->header.size ||
  132. ovr->header.unk1 != ctx->header.unk1 ||
  133. ovr->header.unk2 != ctx->header.unk2 ||
  134. ovr->checksum != ctx->checksum ||
  135. av_strcasecmp(filename, ovr->name) != 0)
  136. continue;
  137. av_log(s, AV_LOG_TRACE, "found override, name = %s\n", ovr->name);
  138. par->sample_rate = ovr->sample_rate;
  139. break;
  140. }
  141. par->channels = 1;
  142. par->channel_layout = AV_CH_LAYOUT_MONO;
  143. par->bits_per_coded_sample = 4;
  144. par->bits_per_raw_sample = 16;
  145. par->block_align = ARGO_CVG_BLOCK_ALIGN;
  146. par->bit_rate = par->sample_rate * par->bits_per_coded_sample;
  147. ctx->num_blocks = (ctx->header.size - 8) / ARGO_CVG_BLOCK_ALIGN;
  148. av_log(s, AV_LOG_TRACE, "num blocks = %u\n", ctx->num_blocks);
  149. avpriv_set_pts_info(st, 64, 1, par->sample_rate);
  150. st->start_time = 0;
  151. st->duration = ctx->num_blocks * ARGO_CVG_SAMPLES_PER_BLOCK;
  152. st->nb_frames = ctx->num_blocks;
  153. return 0;
  154. }
  155. static int argo_cvg_read_packet(AVFormatContext *s, AVPacket *pkt)
  156. {
  157. int ret;
  158. AVStream *st = s->streams[0];
  159. ArgoCVGDemuxContext *ctx = s->priv_data;
  160. if (ctx->blocks_read >= ctx->num_blocks)
  161. return AVERROR_EOF;
  162. ret = av_get_packet(s->pb, pkt, st->codecpar->block_align *
  163. FFMIN(ARGO_CVG_NB_BLOCKS, ctx->num_blocks - ctx->blocks_read));
  164. if (ret < 0)
  165. return ret;
  166. if (ret % st->codecpar->block_align != 0)
  167. return AVERROR_INVALIDDATA;
  168. pkt->stream_index = 0;
  169. pkt->duration = ARGO_CVG_SAMPLES_PER_BLOCK * (ret / st->codecpar->block_align);
  170. pkt->pts = ctx->blocks_read * ARGO_CVG_SAMPLES_PER_BLOCK;
  171. pkt->flags &= ~AV_PKT_FLAG_CORRUPT;
  172. ctx->blocks_read += ret / st->codecpar->block_align;
  173. return 0;
  174. }
  175. static int argo_cvg_seek(AVFormatContext *s, int stream_index,
  176. int64_t pts, int flags)
  177. {
  178. int64_t ret;
  179. ArgoCVGDemuxContext *ctx = s->priv_data;
  180. if (pts != 0 || stream_index != 0)
  181. return AVERROR(EINVAL);
  182. if ((ret = avio_seek(s->pb, ARGO_CVG_HEADER_SIZE, SEEK_SET)) < 0)
  183. return ret;
  184. ctx->blocks_read = 0;
  185. return 0;
  186. }
  187. const AVInputFormat ff_argo_cvg_demuxer = {
  188. .name = "argo_cvg",
  189. .long_name = NULL_IF_CONFIG_SMALL("Argonaut Games CVG"),
  190. .priv_data_size = sizeof(ArgoCVGDemuxContext),
  191. .read_probe = argo_cvg_probe,
  192. .read_header = argo_cvg_read_header,
  193. .read_packet = argo_cvg_read_packet,
  194. .read_seek = argo_cvg_seek,
  195. };