bool load(IFile &file) { TRACE_FN; double usf; // uSeconds per frame this->video_data = file.readAll(); this->video_data_size = file.size(); auto video_path = file.systemPath(); this->file_path = video_path; LogInfo("Read %llu bytes from video", static_cast<unsigned long long>(this->video_data_size)); this->smk_ctx = smk_open_memory(reinterpret_cast<unsigned char *>(this->video_data.get()), static_cast<unsigned long>(this->video_data_size)); if (!this->smk_ctx) { LogWarning("Failed to read SMK file \"%s\"", video_path.cStr()); this->video_data.reset(); return false; } LogInfo("Successfully created SMK context"); if (smk_info_all(this->smk_ctx, nullptr, &this->frame_count, &usf)) { LogWarning("Failed to read SMK file info from \"%s\"", video_path.cStr()); this->video_data.reset(); smk_close(this->smk_ctx); this->smk_ctx = nullptr; return false; } this->frame_time = std::chrono::nanoseconds((unsigned int)(usf * 1000)); LogInfo("Video frame count %lu, ns per frame = %u (USF: %f)", this->frame_count, this->frame_time.count(), usf); unsigned long height, width; if (smk_info_video(this->smk_ctx, &width, &height, nullptr)) { LogWarning("Failed to read SMK video info from \"%s\"", video_path.cStr()); this->video_data.reset(); smk_close(this->smk_ctx); this->smk_ctx = nullptr; return false; } this->frame_size = {width, height}; LogInfo("Video frame size {%u,%u}", this->frame_size.x, this->frame_size.y); auto ret = smk_enable_video(this->smk_ctx, 1); if (ret == SMK_ERROR) { LogWarning("Error enabling video for \"%s\"", video_path.cStr()); return false; } unsigned char audio_track_mask; unsigned char channels[7]; unsigned char bitdepth[7]; unsigned long audio_rate[7]; ret = smk_info_audio(this->smk_ctx, &audio_track_mask, channels, bitdepth, audio_rate); if (ret == SMK_ERROR) { LogWarning("Error reading audio info for \"%s\"", video_path.cStr()); return false; } if (audio_track_mask & SMK_AUDIO_TRACK_0) { // WE only support a single track LogInfo("Audio track: channels %u depth %u rate %lu", (unsigned)channels[0], (unsigned)bitdepth[0], audio_rate[0]); } else { LogWarning("Unsupported audio track mask 0x%02x for \"%s\"", (unsigned)audio_track_mask, video_path.cStr()); return false; } switch (channels[0]) { case 1: // Mono this->audio_format.channels = 1; break; case 2: // Stereo this->audio_format.channels = 2; break; default: LogWarning("Unsupported audio channel count %u for \"%s\"", (unsigned)channels[0], video_path.cStr()); return false; } switch (bitdepth[0]) { case 8: this->audio_format.format = AudioFormat::SampleFormat::PCM_UINT8; this->audio_bytes_per_sample = 1; break; case 16: this->audio_format.format = AudioFormat::SampleFormat::PCM_SINT16; this->audio_bytes_per_sample = 2; break; default: LogWarning("Unsupported audio bit depth %u for \"%s\"", (unsigned)bitdepth[0], video_path.cStr()); return false; } this->audio_format.frequency = audio_rate[0]; ret = smk_enable_audio(this->smk_ctx, 0, 1); if (ret == SMK_ERROR) { LogWarning("Error enabling audio track 0 for \"%s\"", video_path.cStr()); } // Everything looks good return true; }
void process(const char *fn) { FILE *fp; smk s; char outfile[256]; unsigned char b[4]; int i,j,k; unsigned long temp_u; /* all and video info */ unsigned long w, h, f; double usf; unsigned long total_frame_size; /* audio info */ unsigned char a_t, a_c[7], a_d[7]; unsigned long a_r[7]; unsigned char num_tracks = 0; unsigned char **audio_data[7]; unsigned long *audio_size[7]; unsigned long total_audio_size[7] = {0}; unsigned long total_total_audio_size = 0; unsigned char *pal,*frame; unsigned long cur_frame; printf("--------\nsmk2avi processing %s...\n",fn); /* open the smk file */ s = smk_open_file(fn,SMK_MODE_MEMORY); if (s == NULL) goto error; /* get some info about the file */ smk_info_all(s, NULL, &f, &usf); smk_info_video(s, &w, &h, NULL); smk_info_audio(s, &a_t, a_c, a_d, a_r); printf("\t\t\twidth: %u, height: %u, usec/frame: %lf, frames: %u\n",w,h,usf,f); total_frame_size = w * h * 3; /* make 2 passes through the file. first one is to pull all the audio tracks only. */ smk_enable_all(s,a_t); for (i = 0; i < 7; i ++) { if (a_t & (1 << i)) { audio_size[i] = malloc(f * sizeof(unsigned long)); audio_data[i] = malloc(f * sizeof(unsigned char*)); num_tracks ++; } else { audio_size[i] = NULL; audio_data[i] = NULL; } } printf("\tAudio processing frame: "); smk_first(s); for (cur_frame = 0; cur_frame < f; cur_frame ++) { printf("%u... ",cur_frame); fflush(stdout); for (i = 0; i < 7; i ++) { if (audio_size[i] != NULL) { audio_size[i][cur_frame] = smk_get_audio_size(s,i); total_audio_size[i] += smk_get_audio_size(s,i); total_total_audio_size += smk_get_audio_size(s,i); audio_data[i][cur_frame] = malloc(audio_size[i][cur_frame]); memcpy(audio_data[i][cur_frame],smk_get_audio(s,i),audio_size[i][cur_frame]); } } smk_next(s); } printf("done!\n"); smk_enable_all(s,SMK_VIDEO_TRACK); sprintf(outfile,"%s.avi",fn); fp = fopen(outfile,"wb"); printf("Writing AVI file...\n"); // riff header w("RIFF",4); temp_u = 4 + 4 + (8 + 64 + 124 + (num_tracks * 102)) + 8 + (4 + ((total_frame_size + 8) * f) + ( (num_tracks * 8) + total_total_audio_size)); lu(temp_u); w("AVI ",4); { // avi header list LIST; temp_u = 8 + 64 + 124 + (num_tracks * 102); lu(temp_u); w("hdrl",4); { // avi header w("avih",4); lu(56); { lu( (unsigned long)usf ); // microsec per frame temp_u = total_frame_size + total_total_audio_size; lu( temp_u ); // max bytes per sec lu( 1 ); // padding granularity lu( 0 ); // flags lu( f ); // total frames lu( 0 ); // initial frames temp_u = num_tracks + 1; lu( temp_u ); // streams temp_u = total_frame_size + total_total_audio_size; lu( temp_u ); // suggested buf size lu( w ); // width lu( h ); // height lu( 0 ); // reserved (0-3) lu( 0 ); lu( 0 ); lu( 0 ); } // stream list: video stream puts("Video stream header list"); LIST lu(116); w("strl",4); { w("strh",4); lu(56); { w("vids",4); // fourcc type w("DIB ",4); // fourcc handler lu(0); // flags lu(0); // priority + language lu(0); // init frames lu ((unsigned long)usf); // scale lu( 1000000 ); // rate lu(0); // start temp_u = (unsigned long) ((double)f * 100000.0 / usf); lu( temp_u ); // length (time in seconds ?) lu(total_frame_size); // suggested bufsize lu(-1); // quality lu(total_frame_size); // samplesize lu(0); // rcFrame su(w); su(h); // rcFrame: right, bottom } w("strf",4); lu(40); { lu(40); // size lu(w); // width lu(h); // height su(1); // planes su(24); // bpp lu(0); // compression lu(total_frame_size); // total image frame size lu(0); // xpels/meter lu(0); // ypels/meter lu(0); // colors used lu(0); // colors important } } // stream list: audio stream(s) for (i = 0; i < 7; i++) { if (audio_size[i] != NULL) { printf("-> Audio header %d, %dhz, %d bits, %d channels\n",i,a_r[i],a_d[i],a_c[i]); LIST lu(94); w("strl",4); w("strh",4); lu(56); { w("auds",4); // fourcc lu(0); // handler (pcm) lu(0); // flags lu(0); // priority + language lu(0); // initial frames lu( a_c[i]); // scale temp_u = a_r[i] * a_c[i]; lu( temp_u ); // framerate lu(0); // start temp_u = (unsigned long) ((double)f * 100000.0 / usf); lu( temp_u ); // time in seconds temp_u = total_audio_size[i] / a_c[i]; lu( temp_u ); // sugg. buf size lu(-1); // quality temp_u = total_audio_size[i]; lu(temp_u); // sample size lu(0); // rect ?? lu(0); // rect ?? } w("strf",4); lu(18); { su(1); // format su(a_c[i]); // channels lu(a_r[i]); // samples/sec temp_u = a_c[i] * a_r[i] * (a_d[i] / 8); // avg bytes/sec lu(temp_u); temp_u = a_c[i] * (a_d[i] / 8); // avg bytes/sec su(temp_u); su(a_d[i]); su(0); } } } } smk_first(s); printf("\tVideo processing frame:\n"); // movie data LIST temp_u = 4 + ((total_frame_size + 8) * f) + ( (num_tracks * 8) + total_total_audio_size); lu(temp_u); w("movi",4); for (i = 0; i < f; i ++) { w("00db",4); lu(total_frame_size); frame = smk_get_video(s); pal = smk_get_palette(s); if (frame == NULL || pal == NULL) goto error; for (j = h - 1; j >= 0; j--) { for (k = 0; k < w; k++) { w(&pal[frame[(j * w) + k] * 3 + 2],1); w(&pal[frame[(j * w) + k] * 3 + 1],1); w(&pal[frame[(j * w) + k] * 3],1); } } printf("%u...",i); fflush(stdout); smk_next(s); } printf("done!\n"); k = 0; for (i = 0; i < 7; i++) { if (audio_size[i] != NULL) { k ++; sprintf(b,"%02uwb",k); w(b,4); temp_u = total_audio_size[i]; lu(temp_u); for (j = 0; j < f; j++) { w(audio_data[i][j],audio_size[i][j]); } } } } fclose(fp); smk_close(s); printf("done.\n--------\n"); return; error: fclose(fp); smk_close(s); printf("!!HAD ERRORS!!\n--------\n"); return; }