bool readNextFrame() { TRACE_FN; std::lock_guard<std::recursive_mutex> l(this->frame_queue_lock); if (this->stopped) return false; char ret; if (this->current_frame_read == 0) ret = smk_first(this->smk_ctx); else ret = smk_next(this->smk_ctx); if (ret == SMK_ERROR) { LogWarning("Error decoding frame %u", this->current_frame_read); return false; } if (ret == SMK_LAST) { LogInfo("Last frame %u", this->current_frame_read); this->stopped = true; } const unsigned char *palette_data = smk_get_palette(this->smk_ctx); if (!palette_data) { LogWarning("Failed to get palette data for frame %u", this->current_frame_read); return false; } const unsigned char *image_data = smk_get_video(this->smk_ctx); if (!image_data) { LogWarning("Failed to get image data for frame %u", this->current_frame_read); return false; } auto frame = mksp<FrameImage>(); frame->frame = this->current_frame_read; auto img = mksp<PaletteImage>(this->frame_size); frame->image = img; frame->palette = mksp<Palette>(256); PaletteImageLock img_lock(img); memcpy(img_lock.getData(), image_data, this->frame_size.x * this->frame_size.y); for (unsigned int i = 0; i < 256; i++) { auto red = *palette_data++; auto green = *palette_data++; auto blue = *palette_data++; frame->palette->setColour(i, {red, green, blue}); } auto audio_frame = mksp<FrameAudio>(); audio_frame->frame = current_frame_read; audio_frame->format = this->audio_format; unsigned long audio_bytes = smk_get_audio_size(this->smk_ctx, 0); if (audio_bytes == 0) { LogWarning("Error reading audio size for frame %u", this->current_frame_read); return false; } auto sample_count = audio_bytes / (this->audio_bytes_per_sample * this->audio_format.channels); audio_frame->samples.reset(new char[audio_bytes]); audio_frame->sample_count = sample_count; auto sample_pointer = smk_get_audio(this->smk_ctx, 0); if (!sample_pointer) { LogWarning("Error reading audio data for frame %u", this->current_frame_read); return false; } memcpy(audio_frame->samples.get(), sample_pointer, audio_bytes); LogInfo("Read %lu samples bytes, %u samples", audio_bytes, audio_frame->sample_count); this->image_queue.push(frame); this->audio_queue.push(audio_frame); LogInfo("read frame %u", this->current_frame_read); this->current_frame_read++; 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; }