Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 1 | #include "include/smackw32/smackw32.h" |
| 2 | |||
| 3 | #include <assert.h> |
||
| 4 | #include <stddef.h> |
||
| 5 | #include <stdint.h> |
||
| 6 | #include <stdlib.h> |
||
| 7 | #include <string.h> |
||
| 8 | |||
| 9 | #include "harness/hooks.h" |
||
| 10 | #include "harness/trace.h" |
||
| 11 | // lib/libsmacker |
||
| 12 | #include "smacker.h" |
||
| 13 | |||
| 14 | #include "../miniaudio/include/miniaudio/miniaudio.h" |
||
| 15 | extern ma_engine miniaudio_engine; // defined in miniaudio_backend.c |
||
| 16 | extern int gSound_enabled; // defined in globvars.h |
||
| 17 | |||
| 18 | static uint32_t smack_last_frame_time = 0; |
||
| 19 | |||
| 20 | static void copy_palette(Smack* smack) { |
||
| 21 | const unsigned char* pal = smk_get_palette(smack->smk_handle); |
||
| 22 | memcpy(smack->Palette, pal, 256 * 3); |
||
| 23 | } |
||
| 24 | |||
| 25 | Smack* SmackOpen(const char* name, uint32_t flags, uint32_t extrabuf) { |
||
| 26 | ma_format audioformat_ma; |
||
| 27 | ma_paged_audio_buffer_config paged_audio_buffer_config; |
||
| 28 | ma_data_converter_config data_converter_config; |
||
| 29 | unsigned char track_mask_smk; |
||
| 30 | unsigned char channels_smk[7]; |
||
| 31 | unsigned char bitdepth_smk[7]; |
||
| 32 | unsigned long sample_rate_smk[7]; |
||
| 33 | double microsecs_per_frame; |
||
| 34 | Smack* smack; |
||
| 35 | double fps; |
||
| 36 | |||
| 37 | smk smk_handle = smk_open_file(name, SMK_MODE_MEMORY); |
||
| 38 | if (smk_handle == NULL) { |
||
| 39 | return NULL; |
||
| 40 | } |
||
| 41 | |||
| 42 | smack = malloc(sizeof(Smack)); |
||
| 43 | |||
| 44 | // libsmacker doesn't tell us whether the palette is new on each frame or not, so just assume it always is new |
||
| 45 | smack->NewPalette = 1; |
||
| 46 | |||
| 47 | // smk_handle is added to hold a pointer to the underlying libsmacker instance |
||
| 48 | smack->smk_handle = smk_handle; |
||
| 49 | |||
| 50 | smk_info_all(smk_handle, NULL, &smack->Frames, µsecs_per_frame); |
||
| 51 | fps = 1000000.0 / microsecs_per_frame; |
||
| 52 | smack->MSPerFrame = (unsigned long) ((1 / fps) * 1000); // Pierre-Marie Baty -- added type cast |
||
| 53 | smk_info_video(smk_handle, &smack->Width, &smack->Height, NULL); |
||
| 54 | smk_enable_video(smk_handle, 1); |
||
| 55 | |||
| 56 | // initialize video sound if required and present |
||
| 57 | smack->audio_sample_rate = 0; |
||
| 58 | smack->audio_frame_size_in_bytes = 0; |
||
| 59 | smack->audio_paged_buffer = NULL; |
||
| 60 | smack->audio_paged_buffer_data = NULL; |
||
| 61 | smack->audio_converter = NULL; |
||
| 62 | smack->audio_track = NULL; |
||
| 63 | if (!gSound_enabled) { |
||
| 8 | pmbaty | 64 | goto no_audio; |
| 1 | pmbaty | 65 | } |
| 66 | |||
| 67 | // get info about the audio tracks in this video |
||
| 68 | smk_info_audio(smk_handle, &track_mask_smk, channels_smk, bitdepth_smk, sample_rate_smk); |
||
| 69 | if (!(track_mask_smk & SMK_AUDIO_TRACK_0)) { |
||
| 70 | LOG_INFO("Smacker file does not contain audio"); |
||
| 8 | pmbaty | 71 | goto no_audio; |
| 1 | pmbaty | 72 | } |
| 73 | smack->audio_sample_rate = sample_rate_smk[0]; |
||
| 74 | switch (bitdepth_smk[0]) { |
||
| 75 | case 8: |
||
| 76 | audioformat_ma = ma_format_u8; |
||
| 77 | smack->audio_frame_size_in_bytes = 1 * channels_smk[0]; |
||
| 78 | break; |
||
| 79 | case 16: |
||
| 80 | audioformat_ma = ma_format_s16; |
||
| 81 | smack->audio_frame_size_in_bytes = 2 * channels_smk[0]; |
||
| 82 | break; |
||
| 83 | case 24: |
||
| 84 | audioformat_ma = ma_format_s24; |
||
| 85 | smack->audio_frame_size_in_bytes = 3 * channels_smk[0]; |
||
| 86 | break; |
||
| 87 | case 32: |
||
| 88 | audioformat_ma = ma_format_s32; |
||
| 89 | smack->audio_frame_size_in_bytes = 4 * channels_smk[0]; |
||
| 90 | break; |
||
| 91 | default: |
||
| 92 | LOG_WARN("Smacker audio stream has invalid bit depth: %d", bitdepth_smk[0]); |
||
| 8 | pmbaty | 93 | goto no_audio; |
| 1 | pmbaty | 94 | } |
| 95 | |||
| 96 | // allocate and initialize paged buffer data |
||
| 97 | smack->audio_paged_buffer_data = malloc(sizeof(ma_paged_audio_buffer_data)); |
||
| 98 | |||
| 99 | if ((smack->audio_frame_size_in_bytes == 0) || (ma_paged_audio_buffer_data_init(audioformat_ma, channels_smk[0], smack->audio_paged_buffer_data) != MA_SUCCESS)) { |
||
| 100 | LOG_WARN("Failed to create paged audio buffer data"); |
||
| 8 | pmbaty | 101 | goto no_audio; |
| 1 | pmbaty | 102 | } |
| 103 | |||
| 104 | // allocate and initialize paged buffer |
||
| 105 | smack->audio_paged_buffer = malloc(sizeof(ma_paged_audio_buffer)); |
||
| 106 | |||
| 107 | paged_audio_buffer_config = ma_paged_audio_buffer_config_init(smack->audio_paged_buffer_data); |
||
| 108 | if (ma_paged_audio_buffer_init (&paged_audio_buffer_config, smack->audio_paged_buffer) != MA_SUCCESS) { |
||
| 109 | LOG_WARN("Failed to create paged audio buffer for smacker audio stream"); |
||
| 8 | pmbaty | 110 | goto no_audio; |
| 1 | pmbaty | 111 | } |
| 112 | |||
| 113 | // allocate and initialize sound |
||
| 114 | smack->audio_track = malloc(sizeof(ma_sound)); |
||
| 115 | |||
| 116 | if (ma_sound_init_from_data_source(&miniaudio_engine, smack->audio_paged_buffer, MA_SOUND_FLAG_NO_PITCH | MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, smack->audio_track) != MA_SUCCESS) { |
||
| 117 | LOG_WARN("Failed to create sound from data source"); |
||
| 8 | pmbaty | 118 | goto no_audio; |
| 1 | pmbaty | 119 | } |
| 120 | |||
| 8 | pmbaty | 121 | // allocate and initialize data converter if miniaudio engine and Smack file soundtrack sample rates differ |
| 122 | if (ma_engine_get_sample_rate(&miniaudio_engine) != sample_rate_smk[0]) { |
||
| 123 | smack->audio_converter = malloc(sizeof(ma_data_converter)); |
||
| 1 | pmbaty | 124 | |
| 8 | pmbaty | 125 | data_converter_config = ma_data_converter_config_init(audioformat_ma, audioformat_ma, channels_smk[0], channels_smk[0], smack->audio_sample_rate, ma_engine_get_sample_rate (&miniaudio_engine)); |
| 126 | if (ma_data_converter_init(&data_converter_config, NULL, smack->audio_converter) != MA_SUCCESS) { |
||
| 127 | LOG_WARN("Failed to create sound data converter"); |
||
| 128 | goto no_audio; |
||
| 129 | } |
||
| 1 | pmbaty | 130 | } |
| 131 | |||
| 132 | // tell libsmacker we can process audio now |
||
| 133 | smk_enable_audio(smk_handle, 0, 1); |
||
| 8 | pmbaty | 134 | |
| 135 | // load the first frame and return a handle to the Smack file |
||
| 136 | if (smk_first(smk_handle) == SMK_ERROR) { |
||
| 137 | smk_close(smk_handle); |
||
| 138 | free(smack); |
||
| 139 | return NULL; |
||
| 140 | } |
||
| 141 | copy_palette(smack); |
||
| 1 | pmbaty | 142 | return smack; |
| 143 | |||
| 8 | pmbaty | 144 | no_audio: |
| 145 | // no audio or failed to init audio, cleanup audio stuff |
||
| 1 | pmbaty | 146 | if (smack->audio_converter != NULL) { |
| 147 | free(smack->audio_converter); |
||
| 148 | smack->audio_converter = NULL; |
||
| 149 | } |
||
| 150 | if (smack->audio_track != NULL) { |
||
| 151 | ma_sound_uninit(smack->audio_track); |
||
| 152 | free(smack->audio_track); |
||
| 153 | smack->audio_track = NULL; |
||
| 154 | } |
||
| 155 | if (smack->audio_paged_buffer != NULL) { |
||
| 156 | ma_paged_audio_buffer_uninit(smack->audio_paged_buffer); |
||
| 157 | free(smack->audio_paged_buffer); |
||
| 158 | smack->audio_paged_buffer = NULL; |
||
| 159 | } |
||
| 160 | if (smack->audio_paged_buffer_data != NULL) { |
||
| 161 | ma_paged_audio_buffer_data_uninit (smack->audio_paged_buffer_data, NULL); |
||
| 162 | free(smack->audio_paged_buffer_data); |
||
| 163 | smack->audio_paged_buffer_data = NULL; |
||
| 164 | } |
||
| 8 | pmbaty | 165 | |
| 166 | // load the first frame and return a handle to the Smack file |
||
| 167 | if (smk_first(smk_handle) == SMK_ERROR) { |
||
| 168 | smk_close(smk_handle); |
||
| 169 | free(smack); |
||
| 170 | return NULL; |
||
| 171 | } |
||
| 172 | copy_palette(smack); |
||
| 1 | pmbaty | 173 | return smack; |
| 174 | } |
||
| 175 | |||
| 176 | int SmackSoundUseDirectSound(void* dd) { |
||
| 177 | // TODO: do some miniaudio init |
||
| 178 | |||
| 179 | return 0; |
||
| 180 | } |
||
| 181 | |||
| 182 | void SmackToBuffer(Smack* smack, uint32_t left, uint32_t top, uint32_t pitch, uint32_t destheight, void* buf, uint32_t flags) { |
||
| 183 | unsigned long i; // Pierre-Marie Baty -- fixed type |
||
| 184 | |||
| 185 | // minimal implementation |
||
| 186 | assert(left == 0); |
||
| 187 | assert(top == 0); |
||
| 188 | assert(flags == 0); |
||
| 189 | |||
| 190 | char* char_buf = buf; |
||
| 191 | |||
| 192 | const unsigned char* frame = smk_get_video(smack->smk_handle); |
||
| 193 | for (i = 0; i < smack->Height; i++) { |
||
| 194 | memcpy(&char_buf[(i * pitch)], &frame[i * smack->Width], smack->Width); |
||
| 195 | } |
||
| 196 | } |
||
| 197 | |||
| 198 | uint32_t SmackDoFrame(Smack* smack) { |
||
| 199 | const unsigned char *audio_data; |
||
| 200 | unsigned long audio_data_size; |
||
| 201 | ma_paged_audio_buffer_page *newPage; |
||
| 202 | ma_uint64 current_pos; |
||
| 203 | ma_uint64 nb_frames_in; |
||
| 204 | ma_uint64 nb_frames_out; |
||
| 205 | |||
| 206 | // process audio if we have some |
||
| 8 | pmbaty | 207 | if (smack->audio_track != NULL) { |
| 1 | pmbaty | 208 | audio_data = smk_get_audio (smack->smk_handle, 0); |
| 209 | audio_data_size = smk_get_audio_size (smack->smk_handle, 0); |
||
| 210 | if ((audio_data == NULL) || (audio_data_size == 0)) { |
||
| 211 | return 0; |
||
| 212 | } |
||
| 213 | |||
| 214 | if (ma_paged_audio_buffer_get_length_in_pcm_frames (smack->audio_paged_buffer, ¤t_pos) != MA_SUCCESS) { |
||
| 215 | LOG_WARN("ma_paged_audio_buffer_get_length_in_pcm_frames failed"); |
||
| 216 | return 0; |
||
| 217 | } |
||
| 218 | |||
| 8 | pmbaty | 219 | // do we need to convert the sample frequency? |
| 220 | if (smack->audio_converter != NULL) { |
||
| 221 | nb_frames_in = audio_data_size / smack->audio_frame_size_in_bytes; |
||
| 222 | nb_frames_out = nb_frames_in * ma_engine_get_sample_rate (&miniaudio_engine) / smack->audio_sample_rate; |
||
| 1 | pmbaty | 223 | |
| 8 | pmbaty | 224 | if (ma_paged_audio_buffer_data_allocate_page (smack->audio_paged_buffer_data, nb_frames_out, NULL, NULL, &newPage) != MA_SUCCESS) { |
| 225 | LOG_WARN("ma_paged_audio_buffer_data_allocate_page failed"); |
||
| 226 | return 0; |
||
| 227 | } |
||
| 228 | else if (ma_data_converter_process_pcm_frames (smack->audio_converter, audio_data, &nb_frames_in, newPage->pAudioData, &nb_frames_out) != MA_SUCCESS) { |
||
| 229 | LOG_WARN("ma_data_converter_process_pcm_frames failed"); |
||
| 230 | return 0; |
||
| 231 | } |
||
| 232 | else if (ma_paged_audio_buffer_data_append_page (smack->audio_paged_buffer_data, newPage) != MA_SUCCESS) { |
||
| 233 | LOG_WARN("ma_paged_audio_buffer_data_append_page failed"); |
||
| 234 | return 0; |
||
| 235 | } |
||
| 236 | } else { // no sampling frequency conversion needed |
||
| 237 | if (ma_paged_audio_buffer_data_allocate_and_append_page(smack->audio_paged_buffer_data, (ma_uint32) (audio_data_size / (ma_uint64) smack->audio_frame_size_in_bytes), audio_data, NULL) != MA_SUCCESS) { |
||
| 238 | LOG_WARN ("ma_paged_audio_buffer_data_allocate_and_append_page failed"); |
||
| 239 | return 0; |
||
| 240 | } |
||
| 1 | pmbaty | 241 | } |
| 242 | |||
| 8 | pmbaty | 243 | if (!ma_sound_is_playing (smack->audio_track)) |
| 1 | pmbaty | 244 | { |
| 8 | pmbaty | 245 | // seek either at start, or where the accumulated value hasn't played yet |
| 246 | if (ma_sound_seek_to_pcm_frame (smack->audio_track, current_pos) != MA_SUCCESS) { |
||
| 247 | LOG_WARN("ma_sound_seek_to_pcm_frame failed"); |
||
| 1 | pmbaty | 248 | } |
| 8 | pmbaty | 249 | if (ma_sound_start (smack->audio_track) != MA_SUCCESS) { |
| 250 | LOG_WARN("ma_sound_start failed"); |
||
| 1 | pmbaty | 251 | } |
| 252 | } |
||
| 8 | pmbaty | 253 | if (ma_sound_at_end (smack->audio_track)) { |
| 254 | LOG_WARN ("video not playing fast enough: sound starved!"); |
||
| 255 | } |
||
| 1 | pmbaty | 256 | } |
| 257 | |||
| 258 | return 0; |
||
| 259 | } |
||
| 260 | |||
| 261 | void SmackNextFrame(Smack* smack) { |
||
| 262 | smk_next(smack->smk_handle); |
||
| 263 | copy_palette(smack); |
||
| 264 | } |
||
| 265 | |||
| 266 | uint32_t SmackWait(Smack* smack) { |
||
| 267 | uint32_t now = gHarness_platform.GetTicks(); |
||
| 268 | if (now < smack_last_frame_time + smack->MSPerFrame) { |
||
| 269 | gHarness_platform.Sleep(1); |
||
| 270 | return 1; |
||
| 271 | } |
||
| 272 | smack_last_frame_time = now; |
||
| 273 | return 0; |
||
| 274 | } |
||
| 275 | |||
| 276 | void SmackClose(Smack* smack) { |
||
| 277 | if (smack->audio_converter != NULL) { |
||
| 278 | ma_data_converter_uninit(smack->audio_converter, NULL); |
||
| 279 | free(smack->audio_converter); |
||
| 280 | } |
||
| 281 | if (smack->audio_track != NULL) { |
||
| 282 | ma_sound_stop(smack->audio_track); |
||
| 283 | ma_sound_uninit(smack->audio_track); |
||
| 284 | free(smack->audio_track); |
||
| 285 | } |
||
| 286 | if (smack->audio_paged_buffer != NULL) { |
||
| 287 | ma_paged_audio_buffer_uninit(smack->audio_paged_buffer); |
||
| 288 | free(smack->audio_paged_buffer); |
||
| 289 | } |
||
| 290 | if (smack->audio_paged_buffer_data != NULL) { |
||
| 291 | ma_paged_audio_buffer_data_uninit(smack->audio_paged_buffer_data, NULL); |
||
| 292 | free(smack->audio_paged_buffer_data); |
||
| 293 | } |
||
| 294 | smk_close(smack->smk_handle); |
||
| 295 | free(smack); |
||
| 296 | } |