⛏️ index : haiku.git

/*
 * Copyright 2008, Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 * 		Alexandre Deckner <alex@zappotek.com>
 */

#include "VideoFileTexture.h"

#include <Bitmap.h>
#include <Entry.h>
#include <MediaFile.h>
#include <MediaTrack.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <string.h>
#include <stdio.h>


VideoFileTexture::VideoFileTexture(const char* fileName)
	:
	Texture(),
	fMediaFile(NULL),
	fVideoTrack(NULL),
	fVideoBitmap(NULL)
{
	_Load(fileName);
}


VideoFileTexture::~VideoFileTexture()
{
	delete fVideoBitmap;

	if (fMediaFile != NULL) {
		fMediaFile->ReleaseAllTracks();
		fMediaFile->CloseFile();
		delete fMediaFile;
	}
}


void
VideoFileTexture::_Load(const char* fileName)
{
	BEntry entry(fileName);
	entry_ref ref;
	entry.GetRef(&ref);

	fMediaFile = new BMediaFile(&ref);
	status_t err = fMediaFile->InitCheck();
	if (err != B_OK) {
		printf("cannot contruct BMediaFile object -- %s\n", strerror(err));
		return;
	}

	int32 trackCount = fMediaFile->CountTracks();

	for (int32 i = 0; i < trackCount; i++) {
		BMediaTrack* track = fMediaFile->TrackAt(i);
		if (track == NULL) {
			printf("cannot contruct BMediaTrack object\n");
			return;
		}

		// get the encoded format
		media_format format;
		err = track->EncodedFormat(&format);
		if (err != B_OK) {
			printf("BMediaTrack::EncodedFormat error -- %s\n", strerror(err));
			return;
		}

		if (format.type == B_MEDIA_ENCODED_VIDEO) {
			fVideoTrack = track;
			// allocate a bitmap large enough to contain the decoded frame.
			BRect bounds(0.0, 0.0,
				format.u.encoded_video.output.display.line_width - 1.0,
				format.u.encoded_video.output.display.line_count - 1.0);
			fVideoBitmap = new BBitmap(bounds, B_RGB32);

			// specifiy the decoded format. we derive this information from
			// the encoded format.
			format = media_format();
			format.u.raw_video.last_active = (int32) (bounds.Height() - 1.0);
			format.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
			format.u.raw_video.pixel_width_aspect = 1;
			format.u.raw_video.pixel_height_aspect = 3;
			format.u.raw_video.display.format = fVideoBitmap->ColorSpace();
			format.u.raw_video.display.line_width = (int32) bounds.Width();
			format.u.raw_video.display.line_count = (int32) bounds.Height();
			format.u.raw_video.display.bytes_per_row
				= fVideoBitmap->BytesPerRow();

			err = fVideoTrack->DecodedFormat(&format);
			if (err != B_OK) {
				printf("error with BMediaTrack::DecodedFormat() -- %s\n",
					strerror(err));
				return;
			}

			// Create Texture
			glGenTextures(1, &fId);
			glBindTexture(GL_TEXTURE_2D, fId);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexImage2D(GL_TEXTURE_2D, 0, 4,
				(int) fVideoBitmap->Bounds().Width() + 1,
				(int) fVideoBitmap->Bounds().Height() + 1,
				0, GL_BGRA, GL_UNSIGNED_BYTE, fVideoBitmap->Bits());
		}
	}
}


void
VideoFileTexture::Update(float /*dt*/) {
	// TODO loop
	int64 frameCount = 0;
	media_header mh;
	status_t err
		= fVideoTrack->ReadFrames(fVideoBitmap->Bits(), &frameCount, &mh);
	if (err) {
		printf("BMediaTrack::ReadFrames error -- %s\n", strerror(err));
		return;
	}

	glBindTexture(GL_TEXTURE_2D, fId);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
		(int)fVideoBitmap->Bounds().Width() + 1,
		(int)fVideoBitmap->Bounds().Height() + 1,
		GL_BGRA, GL_UNSIGNED_BYTE, fVideoBitmap->Bits());
}