src/lib/util/chdcodec.c
| r14635 | r14636 | |
| 225 | 225 | { |
| 226 | 226 | public: |
| 227 | 227 | // construction/destruction |
| 228 | | chd_flac_compressor(chd_file &chd, bool lossy, bool bigendian); |
| 228 | chd_flac_compressor(chd_file &chd, bool lossy); |
| 229 | 229 | |
| 230 | 230 | // core functionality |
| 231 | 231 | virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest); |
| 232 | 232 | |
| 233 | // static helpers |
| 234 | static UINT32 blocksize(UINT32 bytes); |
| 235 | |
| 233 | 236 | private: |
| 234 | 237 | // internal state |
| 235 | | bool m_swap_endian; |
| 238 | bool m_big_endian; |
| 236 | 239 | flac_encoder m_encoder; |
| 237 | 240 | }; |
| 238 | 241 | |
| 239 | | // big-endian variant |
| 240 | | class chd_flac_compressor_be : public chd_flac_compressor |
| 241 | | { |
| 242 | | public: |
| 243 | | // construction/destruction |
| 244 | | chd_flac_compressor_be(chd_file &chd, bool lossy) |
| 245 | | : chd_flac_compressor(chd, lossy, true) { } |
| 246 | | }; |
| 247 | 242 | |
| 248 | | // little-endian variant |
| 249 | | class chd_flac_compressor_le : public chd_flac_compressor |
| 250 | | { |
| 251 | | public: |
| 252 | | // construction/destruction |
| 253 | | chd_flac_compressor_le(chd_file &chd, bool lossy) |
| 254 | | : chd_flac_compressor(chd, lossy, false) { } |
| 255 | | }; |
| 256 | | |
| 257 | | |
| 258 | 243 | // ======================> chd_flac_decompressor |
| 259 | 244 | |
| 260 | 245 | // FLAC decompressor |
| r14635 | r14636 | |
| 262 | 247 | { |
| 263 | 248 | public: |
| 264 | 249 | // construction/destruction |
| 265 | | chd_flac_decompressor(chd_file &chd, bool lossy, bool bigendian); |
| 250 | chd_flac_decompressor(chd_file &chd, bool lossy); |
| 266 | 251 | |
| 267 | 252 | // core functionality |
| 268 | 253 | virtual void decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen); |
| 269 | 254 | |
| 270 | 255 | private: |
| 271 | 256 | // internal state |
| 272 | | bool m_swap_endian; |
| 257 | bool m_big_endian; |
| 273 | 258 | flac_decoder m_decoder; |
| 274 | 259 | }; |
| 275 | 260 | |
| 276 | | // big-endian variant |
| 277 | | class chd_flac_decompressor_be : public chd_flac_decompressor |
| 278 | | { |
| 279 | | public: |
| 280 | | // construction/destruction |
| 281 | | chd_flac_decompressor_be(chd_file &chd, bool lossy) |
| 282 | | : chd_flac_decompressor(chd, lossy, true) { } |
| 283 | | }; |
| 284 | 261 | |
| 285 | | // little-endian variant |
| 286 | | class chd_flac_decompressor_le : public chd_flac_decompressor |
| 287 | | { |
| 288 | | public: |
| 289 | | // construction/destruction |
| 290 | | chd_flac_decompressor_le(chd_file &chd, bool lossy) |
| 291 | | : chd_flac_decompressor(chd, lossy, false) { } |
| 292 | | }; |
| 293 | | |
| 294 | | |
| 295 | 262 | // ======================> chd_cd_flac_compressor |
| 296 | 263 | |
| 297 | 264 | // CD/FLAC compressor |
| r14635 | r14636 | |
| 305 | 272 | // core functionality |
| 306 | 273 | virtual UINT32 compress(const UINT8 *src, UINT32 srclen, UINT8 *dest); |
| 307 | 274 | |
| 275 | // static helpers |
| 276 | static UINT32 blocksize(UINT32 bytes); |
| 277 | |
| 308 | 278 | private: |
| 309 | 279 | // internal state |
| 310 | 280 | bool m_swap_endian; |
| r14635 | r14636 | |
| 390 | 360 | { CHD_CODEC_ZLIB, false, "Deflate", &chd_codec_list::construct_compressor<chd_zlib_compressor>, &chd_codec_list::construct_decompressor<chd_zlib_decompressor> }, |
| 391 | 361 | { CHD_CODEC_LZMA, false, "LZMA", &chd_codec_list::construct_compressor<chd_lzma_compressor>, &chd_codec_list::construct_decompressor<chd_lzma_decompressor> }, |
| 392 | 362 | { CHD_CODEC_HUFFMAN, false, "Huffman", &chd_codec_list::construct_compressor<chd_huffman_compressor>, &chd_codec_list::construct_decompressor<chd_huffman_decompressor> }, |
| 393 | | { CHD_CODEC_FLAC_BE, false, "FLAC, big-endian", &chd_codec_list::construct_compressor<chd_flac_compressor_be>, &chd_codec_list::construct_decompressor<chd_flac_decompressor_be> }, |
| 394 | | { CHD_CODEC_FLAC_LE, false, "FLAC, little-endian", &chd_codec_list::construct_compressor<chd_flac_compressor_le>, &chd_codec_list::construct_decompressor<chd_flac_decompressor_le> }, |
| 363 | { CHD_CODEC_FLAC, false, "FLAC", &chd_codec_list::construct_compressor<chd_flac_compressor>, &chd_codec_list::construct_decompressor<chd_flac_decompressor> }, |
| 395 | 364 | { CHD_CODEC_CD_FLAC, false, "CD FLAC", &chd_codec_list::construct_compressor<chd_cd_flac_compressor>, &chd_codec_list::construct_decompressor<chd_cd_flac_decompressor> }, |
| 396 | 365 | { CHD_CODEC_AVHUFF, false, "A/V Huffman", &chd_codec_list::construct_compressor<chd_avhuff_compressor>, &chd_codec_list::construct_decompressor<chd_avhuff_decompressor> }, |
| 397 | 366 | }; |
| r14635 | r14636 | |
| 1157 | 1126 | // chd_flac_compressor - constructor |
| 1158 | 1127 | //------------------------------------------------- |
| 1159 | 1128 | |
| 1160 | | chd_flac_compressor::chd_flac_compressor(chd_file &chd, bool lossy, bool bigendian) |
| 1129 | chd_flac_compressor::chd_flac_compressor(chd_file &chd, bool lossy) |
| 1161 | 1130 | : chd_compressor(chd, lossy) |
| 1162 | 1131 | { |
| 1163 | 1132 | // determine whether we want native or swapped samples |
| 1164 | 1133 | UINT16 native_endian = 0; |
| 1165 | 1134 | *reinterpret_cast<UINT8 *>(&native_endian) = 1; |
| 1166 | | if (native_endian == 1) |
| 1167 | | m_swap_endian = bigendian; |
| 1168 | | else |
| 1169 | | m_swap_endian = !bigendian; |
| 1170 | | |
| 1135 | m_big_endian = (native_endian == 0x100); |
| 1136 | |
| 1171 | 1137 | // configure the encoder |
| 1172 | 1138 | m_encoder.set_sample_rate(44100); |
| 1173 | 1139 | m_encoder.set_num_channels(2); |
| 1174 | | m_encoder.set_block_size(chd.hunk_bytes() / 4); |
| 1140 | m_encoder.set_block_size(blocksize(chd.hunk_bytes())); |
| 1175 | 1141 | m_encoder.set_strip_metadata(true); |
| 1176 | 1142 | } |
| 1177 | 1143 | |
| r14635 | r14636 | |
| 1182 | 1148 | |
| 1183 | 1149 | UINT32 chd_flac_compressor::compress(const UINT8 *src, UINT32 srclen, UINT8 *dest) |
| 1184 | 1150 | { |
| 1185 | | // reset and encode |
| 1186 | | m_encoder.reset(dest, chd().hunk_bytes()); |
| 1187 | | if (!m_encoder.encode_interleaved(reinterpret_cast<const INT16 *>(src), srclen / 4, m_swap_endian)) |
| 1151 | // reset and encode big-endian |
| 1152 | m_encoder.reset(dest + 1, chd().hunk_bytes() - 1); |
| 1153 | if (!m_encoder.encode_interleaved(reinterpret_cast<const INT16 *>(src), srclen / 4, !m_big_endian)) |
| 1188 | 1154 | throw CHDERR_COMPRESSION_ERROR; |
| 1189 | | |
| 1190 | | // finish up |
| 1191 | | UINT32 complen = m_encoder.finish(); |
| 1192 | | if (complen >= chd().hunk_bytes()) |
| 1155 | UINT32 complen_be = m_encoder.finish(); |
| 1156 | |
| 1157 | // reset and encode little-endian |
| 1158 | m_encoder.reset(dest + 1, chd().hunk_bytes() - 1); |
| 1159 | if (!m_encoder.encode_interleaved(reinterpret_cast<const INT16 *>(src), srclen / 4, m_big_endian)) |
| 1193 | 1160 | throw CHDERR_COMPRESSION_ERROR; |
| 1194 | | return complen; |
| 1161 | UINT32 complen_le = m_encoder.finish(); |
| 1162 | |
| 1163 | // pick the best one and add a byte |
| 1164 | UINT32 complen = MIN(complen_le, complen_be); |
| 1165 | if (complen + 1 >= chd().hunk_bytes()) |
| 1166 | throw CHDERR_COMPRESSION_ERROR; |
| 1167 | |
| 1168 | // if big-endian was better, re-do it |
| 1169 | dest[0] = 'L'; |
| 1170 | if (complen != complen_le) |
| 1171 | { |
| 1172 | dest[0] = 'B'; |
| 1173 | m_encoder.reset(dest + 1, chd().hunk_bytes() - 1); |
| 1174 | if (!m_encoder.encode_interleaved(reinterpret_cast<const INT16 *>(src), srclen / 4, !m_big_endian)) |
| 1175 | throw CHDERR_COMPRESSION_ERROR; |
| 1176 | m_encoder.finish(); |
| 1177 | } |
| 1178 | return complen + 1; |
| 1195 | 1179 | } |
| 1196 | 1180 | |
| 1197 | 1181 | |
| 1182 | //------------------------------------------------- |
| 1183 | // blocksize - return the optimal block size |
| 1184 | //------------------------------------------------- |
| 1198 | 1185 | |
| 1186 | UINT32 chd_flac_compressor::blocksize(UINT32 bytes) |
| 1187 | { |
| 1188 | // determine FLAC block size, which must be 16-65535 |
| 1189 | // clamp to 2k since that's supposed to be the sweet spot |
| 1190 | UINT32 blocksize = bytes / 4; |
| 1191 | while (blocksize > 2048) |
| 1192 | blocksize /= 2; |
| 1193 | return blocksize; |
| 1194 | } |
| 1195 | |
| 1196 | |
| 1197 | |
| 1199 | 1198 | //************************************************************************** |
| 1200 | 1199 | // FLAC DECOMPRESSOR |
| 1201 | 1200 | //************************************************************************** |
| r14635 | r14636 | |
| 1204 | 1203 | // chd_flac_decompressor - constructor |
| 1205 | 1204 | //------------------------------------------------- |
| 1206 | 1205 | |
| 1207 | | chd_flac_decompressor::chd_flac_decompressor(chd_file &chd, bool lossy, bool bigendian) |
| 1206 | chd_flac_decompressor::chd_flac_decompressor(chd_file &chd, bool lossy) |
| 1208 | 1207 | : chd_decompressor(chd, lossy) |
| 1209 | 1208 | { |
| 1210 | 1209 | // determine whether we want native or swapped samples |
| 1211 | 1210 | UINT16 native_endian = 0; |
| 1212 | 1211 | *reinterpret_cast<UINT8 *>(&native_endian) = 1; |
| 1213 | | if (native_endian == 1) |
| 1214 | | m_swap_endian = bigendian; |
| 1215 | | else |
| 1216 | | m_swap_endian = !bigendian; |
| 1212 | m_big_endian = (native_endian == 0x100); |
| 1217 | 1213 | } |
| 1218 | 1214 | |
| 1219 | 1215 | |
| r14635 | r14636 | |
| 1224 | 1220 | |
| 1225 | 1221 | void chd_flac_decompressor::decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen) |
| 1226 | 1222 | { |
| 1223 | // determine the endianness |
| 1224 | bool swap_endian; |
| 1225 | if (src[0] == 'L') |
| 1226 | swap_endian = m_big_endian; |
| 1227 | else if (src[0] == 'B') |
| 1228 | swap_endian = !m_big_endian; |
| 1229 | else |
| 1230 | throw CHDERR_DECOMPRESSION_ERROR; |
| 1231 | |
| 1227 | 1232 | // reset and decode |
| 1228 | | if (!m_decoder.reset(44100, 2, chd().hunk_bytes() / 4, src, complen)) |
| 1233 | if (!m_decoder.reset(44100, 2, chd_flac_compressor::blocksize(destlen), src + 1, complen - 1)) |
| 1229 | 1234 | throw CHDERR_DECOMPRESSION_ERROR; |
| 1230 | | if (!m_decoder.decode_interleaved(reinterpret_cast<INT16 *>(dest), destlen / 4, m_swap_endian)) |
| 1235 | if (!m_decoder.decode_interleaved(reinterpret_cast<INT16 *>(dest), destlen / 4, swap_endian)) |
| 1231 | 1236 | throw CHDERR_DECOMPRESSION_ERROR; |
| 1232 | 1237 | |
| 1233 | 1238 | // finish up |
| r14635 | r14636 | |
| 1260 | 1265 | // configure the encoder |
| 1261 | 1266 | m_encoder.set_sample_rate(44100); |
| 1262 | 1267 | m_encoder.set_num_channels(2); |
| 1263 | | m_encoder.set_block_size((chd.hunk_bytes() / CD_FRAME_SIZE) * (CD_MAX_SECTOR_DATA/4)); |
| 1268 | m_encoder.set_block_size(blocksize((chd.hunk_bytes() / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA)); |
| 1264 | 1269 | m_encoder.set_strip_metadata(true); |
| 1265 | 1270 | |
| 1266 | 1271 | // initialize the deflater |
| r14635 | r14636 | |
| 1333 | 1338 | } |
| 1334 | 1339 | |
| 1335 | 1340 | |
| 1341 | //------------------------------------------------- |
| 1342 | // blocksize - return the optimal block size |
| 1343 | //------------------------------------------------- |
| 1336 | 1344 | |
| 1345 | UINT32 chd_cd_flac_compressor::blocksize(UINT32 bytes) |
| 1346 | { |
| 1347 | // for CDs it seems that CD_MAX_SECTOR_DATA is the right target |
| 1348 | UINT32 blocksize = bytes / 4; |
| 1349 | while (blocksize > CD_MAX_SECTOR_DATA) |
| 1350 | blocksize /= 2; |
| 1351 | return blocksize; |
| 1352 | } |
| 1353 | |
| 1354 | |
| 1355 | |
| 1337 | 1356 | //************************************************************************** |
| 1338 | 1357 | // CD FLAC DECOMPRESSOR |
| 1339 | 1358 | //************************************************************************** |
| r14635 | r14636 | |
| 1387 | 1406 | void chd_cd_flac_decompressor::decompress(const UINT8 *src, UINT32 complen, UINT8 *dest, UINT32 destlen) |
| 1388 | 1407 | { |
| 1389 | 1408 | // reset and decode |
| 1390 | | UINT32 frames = chd().hunk_bytes() / CD_FRAME_SIZE; |
| 1391 | | if (!m_decoder.reset(44100, 2, frames * CD_MAX_SECTOR_DATA/4, src, complen)) |
| 1409 | UINT32 frames = destlen / CD_FRAME_SIZE; |
| 1410 | if (!m_decoder.reset(44100, 2, chd_cd_flac_compressor::blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) |
| 1392 | 1411 | throw CHDERR_DECOMPRESSION_ERROR; |
| 1393 | 1412 | UINT8 *buffer = m_buffer; |
| 1394 | 1413 | if (!m_decoder.decode_interleaved(reinterpret_cast<INT16 *>(buffer), frames * CD_MAX_SECTOR_DATA/4, m_swap_endian)) |