示例#1
0
void VideoStreamPlaybackTheora::video_write(void) {
	th_ycbcr_buffer yuv;
	th_decode_ycbcr_out(td, yuv);

	int pitch = 4;
	frame_data.resize(size.x * size.y * pitch);
	{
		PoolVector<uint8_t>::Write w = frame_data.write();
		char *dst = (char *)w.ptr();

		//uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y/2);

		if (px_fmt == TH_PF_444) {

			yuv444_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);

		} else if (px_fmt == TH_PF_422) {

			yuv422_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);

		} else if (px_fmt == TH_PF_420) {

			yuv420_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[2].data, (uint8_t *)yuv[1].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);
		};

		format = Image::FORMAT_RGBA8;
	}

	Ref<Image> img = memnew(Image(size.x, size.y, 0, Image::FORMAT_RGBA8, frame_data)); //zero copy image creation

	texture->set_data(img); //zero copy send to visual server

	frames_pending = 1;
}
示例#2
0
void VideoStreamPlaybackWebm::update(float p_delta) {

	if ((!playing || paused) || !video)
		return;

	time += p_delta;

	if (time < video_pos) {
		return;
	}

	bool audio_buffer_full = false;

	if (samples_offset > -1) {

		//Mix remaining samples
		const int to_read = num_decoded_samples - samples_offset;
		const int mixed = mix_callback(mix_udata, pcm + samples_offset * webm->getChannels(), to_read);
		if (mixed != to_read) {

			samples_offset += mixed;
			audio_buffer_full = true;
		} else {

			samples_offset = -1;
		}
	}

	const bool hasAudio = (audio && mix_callback);
	while ((hasAudio && !audio_buffer_full && !has_enough_video_frames()) ||
			(!hasAudio && video_frames_pos == 0)) {

		if (hasAudio && !audio_buffer_full && audio_frame->isValid() &&
				audio->getPCMF(*audio_frame, pcm, num_decoded_samples) && num_decoded_samples > 0) {

			const int mixed = mix_callback(mix_udata, pcm, num_decoded_samples);

			if (mixed != num_decoded_samples) {
				samples_offset = mixed;
				audio_buffer_full = true;
			}
		}

		WebMFrame *video_frame;
		if (video_frames_pos >= video_frames_capacity) {

			WebMFrame **video_frames_new = (WebMFrame **)memrealloc(video_frames, ++video_frames_capacity * sizeof(void *));
			ERR_FAIL_COND(!video_frames_new); //Out of memory
			(video_frames = video_frames_new)[video_frames_capacity - 1] = memnew(WebMFrame);
		}
		video_frame = video_frames[video_frames_pos];

		if (!webm->readFrame(video_frame, audio_frame)) //This will invalidate frames
			break; //Can't demux, EOS?

		if (video_frame->isValid())
			++video_frames_pos;
	};

	bool video_frame_done = false;
	while (video_frames_pos > 0 && !video_frame_done) {

		WebMFrame *video_frame = video_frames[0];

		// It seems VPXDecoder::decode has to be executed even though we might skip this frame
		if (video->decode(*video_frame)) {

			VPXDecoder::IMAGE_ERROR err;
			VPXDecoder::Image image;

			if (should_process(*video_frame)) {

				if ((err = video->getImage(image)) != VPXDecoder::NO_FRAME) {

					if (err == VPXDecoder::NO_ERROR && image.w == webm->getWidth() && image.h == webm->getHeight()) {

						PoolVector<uint8_t>::Write w = frame_data.write();
						bool converted = false;

						if (image.chromaShiftW == 1 && image.chromaShiftH == 1) {

							yuv420_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
							// 								libyuv::I420ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
							converted = true;
						} else if (image.chromaShiftW == 1 && image.chromaShiftH == 0) {

							yuv422_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
							// 								libyuv::I422ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
							converted = true;
						} else if (image.chromaShiftW == 0 && image.chromaShiftH == 0) {

							yuv444_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
							// 								libyuv::I444ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
							converted = true;
						} else if (image.chromaShiftW == 2 && image.chromaShiftH == 0) {

							// 								libyuv::I411ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
							// 								converted = true;
						}

						if (converted) {
							Ref<Image> img = memnew(Image(image.w, image.h, 0, Image::FORMAT_RGBA8, frame_data));
							texture->set_data(img); //Zero copy send to visual server
							video_frame_done = true;
						}
					}
				}
			}
		}

		video_pos = video_frame->time;
		memmove(video_frames, video_frames + 1, (--video_frames_pos) * sizeof(void *));
		video_frames[video_frames_pos] = video_frame;
	}

	if (video_frames_pos == 0 && webm->isEOS())
		stop();
}
示例#3
0
void VideoStreamTheora::video_write(void){
	th_ycbcr_buffer yuv;
	int y_offset, uv_offset;
	th_decode_ycbcr_out(td,yuv);

	y_offset=(ti.pic_x&~1)+yuv[0].stride*(ti.pic_y&~1);

	/*
	{
		int pixels = size.x * size.y;
		frame_data.resize(pixels * 4);
		DVector<uint8_t>::Write w = frame_data.write();
		char* dst = (char*)w.ptr();
		int p = 0;
		for (int i=0; i<size.y; i++) {

			char *in_y  = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
			char *out = dst + (int)size.x * 4 * i;
			for (int j=0;j<size.x;j++) {

				dst[p++] = in_y[j];
				dst[p++] = in_y[j];
				dst[p++] = in_y[j];
				dst[p++] = 255;
			};
		}
		format = Image::FORMAT_RGBA;
	}
	//	*/

	//*

	int pitch = 4;
	frame_data.resize(size.x * size.y * pitch);
	DVector<uint8_t>::Write w = frame_data.write();
	char* dst = (char*)w.ptr();

	uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y/2);

	if (px_fmt == TH_PF_444) {

		yuv444_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[1].data, (uint8_t*)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);

	} else if (px_fmt == TH_PF_422) {

		yuv422_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[1].data, (uint8_t*)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);

	} else if (px_fmt == TH_PF_420) {

		yuv420_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[2].data, (uint8_t*)yuv[1].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);
	};

	format = Image::FORMAT_RGBA;

	/*

	if (px_fmt == TH_PF_444) {

		int pitch = 3;
		frame_data.resize(size.x * size.y * pitch);
		DVector<uint8_t>::Write w = frame_data.write();
		char* dst = (char*)w.ptr();

		for(int i=0;i<size.y;i++) {

			char *in_y  = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
			char *out = dst + (int)size.x * pitch * i;
			char *in_u  = (char *)yuv[1].data+uv_offset+yuv[1].stride*i;
			char *in_v  = (char *)yuv[2].data+uv_offset+yuv[2].stride*i;
			for (int j=0;j<size.x;j++) {

				out[j*3+0] = in_y[j];
				out[j*3+1] = in_u[j];
				out[j*3+2] = in_v[j];
			};
		}

		format = Image::FORMAT_YUV_444;

	} else {

		int div;
		if (px_fmt!=TH_PF_422) {
			div = 2;
		}

		bool rgba = true;
		if (rgba) {

			int pitch = 4;
			frame_data.resize(size.x * size.y * pitch);
			DVector<uint8_t>::Write w = frame_data.write();
			char* dst = (char*)w.ptr();

			uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y / div);
			for(int i=0;i<size.y;i++) {
				char *in_y  = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
				char *in_u  = (char *)yuv[1].data+uv_offset+yuv[1].stride*(i/div);
				char *in_v  = (char *)yuv[2].data+uv_offset+yuv[2].stride*(i/div);
				uint8_t *out = (uint8_t*)dst + (int)size.x * pitch * i;
				int ofs = 0;
				for (int j=0;j<size.x;j++) {

					uint8_t y, u, v;
					y = in_y[j];
					u = in_u[j/2];
					v = in_v[j/2];

					int32_t r = Math::fast_ftoi(1.164 * (y - 16) + 1.596 * (v - 128));
					int32_t g = Math::fast_ftoi(1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128));
					int32_t b = Math::fast_ftoi(1.164 * (y - 16) + 2.018 * (u - 128));

					out[ofs++] = CLAMP(r, 0, 255);
					out[ofs++] = CLAMP(g, 0, 255);
					out[ofs++] = CLAMP(b, 0, 255);
					out[ofs++] = 255;
				}
			}

			format = Image::FORMAT_RGBA;

		} else {

			int pitch = 2;
			frame_data.resize(size.x * size.y * pitch);
			DVector<uint8_t>::Write w = frame_data.write();
			char* dst = (char*)w.ptr();

			uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y / div);
			for(int i=0;i<size.y;i++) {
				char *in_y  = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
				char *out = dst + (int)size.x * pitch * i;
				for (int j=0;j<size.x;j++)
					out[j*2] = in_y[j];
				char *in_u  = (char *)yuv[1].data+uv_offset+yuv[1].stride*(i/div);
				char *in_v  = (char *)yuv[2].data+uv_offset+yuv[2].stride*(i/div);
				for (int j=0;j<(int)size.x>>1;j++) {
					out[j*4+1] = in_u[j];
					out[j*4+3] = in_v[j];
				}
			}

			format = Image::FORMAT_YUV_422;
		};
	};
	//	*/

	frames_pending = 1;
}
示例#4
0
void VideoStreamPlaybackTheora::video_write(void) {
	th_ycbcr_buffer yuv;
	th_decode_ycbcr_out(td, yuv);

	// FIXME: The way stuff is commented out with `//*/` closing comments
	// sounds very fishy...

	/*
	int y_offset, uv_offset;
	y_offset=(ti.pic_x&~1)+yuv[0].stride*(ti.pic_y&~1);

	{
		int pixels = size.x * size.y;
		frame_data.resize(pixels * 4);
		PoolVector<uint8_t>::Write w = frame_data.write();
		char* dst = (char*)w.ptr();
		int p = 0;
		for (int i=0; i<size.y; i++) {

			char *in_y  = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
			char *out = dst + (int)size.x * 4 * i;
			for (int j=0;j<size.x;j++) {

				dst[p++] = in_y[j];
				dst[p++] = in_y[j];
				dst[p++] = in_y[j];
				dst[p++] = 255;
			};
		}
		format = Image::FORMAT_RGBA8;
	}
		//*/

	//*

	int pitch = 4;
	frame_data.resize(size.x * size.y * pitch);
	{
		PoolVector<uint8_t>::Write w = frame_data.write();
		char *dst = (char *)w.ptr();

		//uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y/2);

		if (px_fmt == TH_PF_444) {

			yuv444_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);

		} else if (px_fmt == TH_PF_422) {

			yuv422_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[1].data, (uint8_t *)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);

		} else if (px_fmt == TH_PF_420) {

			yuv420_2_rgb8888((uint8_t *)dst, (uint8_t *)yuv[0].data, (uint8_t *)yuv[2].data, (uint8_t *)yuv[1].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x << 2, 0);
		};

		format = Image::FORMAT_RGBA8;
	}

	Ref<Image> img = memnew(Image(size.x, size.y, 0, Image::FORMAT_RGBA8, frame_data)); //zero copy image creation

	texture->set_data(img); //zero copy send to visual server

	/*

	if (px_fmt == TH_PF_444) {

		int pitch = 3;
		frame_data.resize(size.x * size.y * pitch);
		PoolVector<uint8_t>::Write w = frame_data.write();
		char* dst = (char*)w.ptr();

		for(int i=0;i<size.y;i++) {

			char *in_y  = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
			char *out = dst + (int)size.x * pitch * i;
			char *in_u  = (char *)yuv[1].data+uv_offset+yuv[1].stride*i;
			char *in_v  = (char *)yuv[2].data+uv_offset+yuv[2].stride*i;
			for (int j=0;j<size.x;j++) {

				out[j*3+0] = in_y[j];
				out[j*3+1] = in_u[j];
				out[j*3+2] = in_v[j];
			};
		}

		format = Image::FORMAT_YUV_444;

	} else {

		int div;
		if (px_fmt!=TH_PF_422) {
			div = 2;
		}

		bool rgba = true;
		if (rgba) {

			int pitch = 4;
			frame_data.resize(size.x * size.y * pitch);
			PoolVector<uint8_t>::Write w = frame_data.write();
			char* dst = (char*)w.ptr();

			uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y / div);
			for(int i=0;i<size.y;i++) {
				char *in_y  = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
				char *in_u  = (char *)yuv[1].data+uv_offset+yuv[1].stride*(i/div);
				char *in_v  = (char *)yuv[2].data+uv_offset+yuv[2].stride*(i/div);
				uint8_t *out = (uint8_t*)dst + (int)size.x * pitch * i;
				int ofs = 0;
				for (int j=0;j<size.x;j++) {

					uint8_t y, u, v;
					y = in_y[j];
					u = in_u[j/2];
					v = in_v[j/2];

					int32_t r = Math::fast_ftoi(1.164 * (y - 16) + 1.596 * (v - 128));
					int32_t g = Math::fast_ftoi(1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128));
					int32_t b = Math::fast_ftoi(1.164 * (y - 16) + 2.018 * (u - 128));

					out[ofs++] = CLAMP(r, 0, 255);
					out[ofs++] = CLAMP(g, 0, 255);
					out[ofs++] = CLAMP(b, 0, 255);
					out[ofs++] = 255;
				}
			}

			format = Image::FORMAT_RGBA8;

		} else {

			int pitch = 2;
			frame_data.resize(size.x * size.y * pitch);
			PoolVector<uint8_t>::Write w = frame_data.write();
			char* dst = (char*)w.ptr();

			uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y / div);
			for(int i=0;i<size.y;i++) {
				char *in_y  = (char *)yuv[0].data+y_offset+yuv[0].stride*i;
				char *out = dst + (int)size.x * pitch * i;
				for (int j=0;j<size.x;j++)
					out[j*2] = in_y[j];
				char *in_u  = (char *)yuv[1].data+uv_offset+yuv[1].stride*(i/div);
				char *in_v  = (char *)yuv[2].data+uv_offset+yuv[2].stride*(i/div);
				for (int j=0;j<(int)size.x>>1;j++) {
					out[j*4+1] = in_u[j];
					out[j*4+3] = in_v[j];
				}
			}

			format = Image::FORMAT_YUV_422;
		};
	};
		//*/

	frames_pending = 1;
}