Commit | Line | Data |
---|---|---|
3719602c PC |
1 | /*************************************************************************** |
2 | ||
3 | libchdr_flac_codec.c | |
4 | ||
5 | MAME Compressed Hunks of Data file format | |
6 | ||
7 | **************************************************************************** | |
8 | ||
9 | Copyright Aaron Giles | |
10 | All rights reserved. | |
11 | ||
12 | Redistribution and use in source and binary forms, with or without | |
13 | modification, are permitted provided that the following conditions are | |
14 | met: | |
15 | ||
16 | * Redistributions of source code must retain the above copyright | |
17 | notice, this list of conditions and the following disclaimer. | |
18 | * Redistributions in binary form must reproduce the above copyright | |
19 | notice, this list of conditions and the following disclaimer in | |
20 | the documentation and/or other materials provided with the | |
21 | distribution. | |
22 | * Neither the name 'MAME' nor the names of its contributors may be | |
23 | used to endorse or promote products derived from this software | |
24 | without specific prior written permission. | |
25 | ||
26 | THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR | |
27 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
28 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
29 | DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, | |
30 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
31 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
33 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
34 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
35 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
36 | POSSIBILITY OF SUCH DAMAGE. | |
37 | ||
38 | ***************************************************************************/ | |
39 | ||
40 | #include <stddef.h> | |
41 | #include <stdint.h> | |
42 | #include <stdio.h> | |
43 | #include <stdlib.h> | |
44 | #include <string.h> | |
45 | #include <libchdr/chd.h> | |
46 | #include <libchdr/minmax.h> | |
47 | #include <libchdr/cdrom.h> | |
48 | #include <libchdr/flac.h> | |
49 | #include <libchdr/huffman.h> | |
50 | #include <zlib.h> | |
51 | ||
52 | #include <retro_inline.h> | |
53 | #include <streams/file_stream.h> | |
54 | ||
55 | #define TRUE 1 | |
56 | #define FALSE 0 | |
57 | ||
58 | /*************************************************************************** | |
59 | * CD FLAC DECOMPRESSOR | |
60 | *************************************************************************** | |
61 | */ | |
62 | ||
63 | /*------------------------------------------------------ | |
64 | * cdfl_codec_blocksize - return the optimal block size | |
65 | *------------------------------------------------------ | |
66 | */ | |
67 | ||
68 | static uint32_t cdfl_codec_blocksize(uint32_t bytes) | |
69 | { | |
70 | /* determine FLAC block size, which must be 16-65535 | |
71 | * clamp to 2k since that's supposed to be the sweet spot */ | |
72 | uint32_t hunkbytes = bytes / 4; | |
73 | while (hunkbytes > 2048) | |
74 | hunkbytes /= 2; | |
75 | return hunkbytes; | |
76 | } | |
77 | ||
78 | chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) | |
79 | { | |
80 | #ifdef WANT_SUBCODE | |
81 | chd_error ret; | |
82 | #endif | |
83 | uint16_t native_endian = 0; | |
84 | cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; | |
85 | ||
86 | /* make sure the CHD's hunk size is an even multiple of the frame size */ | |
87 | if (hunkbytes % CD_FRAME_SIZE != 0) | |
88 | return CHDERR_CODEC_ERROR; | |
89 | ||
90 | cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); | |
91 | if (cdfl->buffer == NULL) | |
92 | return CHDERR_OUT_OF_MEMORY; | |
93 | ||
94 | /* determine whether we want native or swapped samples */ | |
95 | *(uint8_t *)(&native_endian) = 1; | |
96 | cdfl->swap_endian = (native_endian & 1); | |
97 | ||
98 | #ifdef WANT_SUBCODE | |
99 | /* init zlib inflater */ | |
100 | ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); | |
101 | if (ret != CHDERR_NONE) | |
102 | return ret; | |
103 | #endif | |
104 | ||
105 | /* flac decoder init */ | |
106 | flac_decoder_init(&cdfl->decoder); | |
107 | if (cdfl->decoder.decoder == NULL) | |
108 | return CHDERR_OUT_OF_MEMORY; | |
109 | ||
110 | return CHDERR_NONE; | |
111 | } | |
112 | ||
113 | void cdfl_codec_free(void *codec) | |
114 | { | |
115 | cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; | |
116 | flac_decoder_free(&cdfl->decoder); | |
117 | #ifdef WANT_SUBCODE | |
118 | zlib_codec_free(&cdfl->subcode_decompressor); | |
119 | #endif | |
120 | if (cdfl->buffer) | |
121 | free(cdfl->buffer); | |
122 | } | |
123 | ||
124 | chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) | |
125 | { | |
126 | uint32_t framenum; | |
127 | uint8_t *buffer; | |
128 | #ifdef WANT_SUBCODE | |
129 | uint32_t offset; | |
130 | chd_error ret; | |
131 | #endif | |
132 | cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; | |
133 | ||
134 | /* reset and decode */ | |
135 | uint32_t frames = destlen / CD_FRAME_SIZE; | |
136 | ||
137 | if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) | |
138 | return CHDERR_DECOMPRESSION_ERROR; | |
139 | buffer = &cdfl->buffer[0]; | |
140 | if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian)) | |
141 | return CHDERR_DECOMPRESSION_ERROR; | |
142 | ||
143 | #ifdef WANT_SUBCODE | |
144 | /* inflate the subcode data */ | |
145 | offset = flac_decoder_finish(&cdfl->decoder); | |
146 | ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); | |
147 | if (ret != CHDERR_NONE) | |
148 | return ret; | |
149 | #else | |
150 | flac_decoder_finish(&cdfl->decoder); | |
151 | #endif | |
152 | ||
153 | /* reassemble the data */ | |
154 | for (framenum = 0; framenum < frames; framenum++) | |
155 | { | |
156 | memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); | |
157 | #ifdef WANT_SUBCODE | |
158 | memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); | |
159 | #endif | |
160 | } | |
161 | ||
162 | return CHDERR_NONE; | |
163 | } |