예제 #1
0
	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;
	}
예제 #2
0
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;
	
}