1/*	PROJECT:		3Dmov
2	AUTHORS:		Zenja Solaja
3	COPYRIGHT:		2009 Haiku Inc
4	DESCRIPTION:	Haiku version of the famous BeInc demo 3Dmov
5					This file handles video playback for ViewObject base class.
6*/
7
8#include <stdio.h>
9#include <Bitmap.h>
10#include <Screen.h>
11
12#include "ViewObject.h"
13#include "Video.h"
14
15/*	FUNCTION:		Video :: Video
16	ARGUMENTS:		ref
17	RETURN:			n/a
18	DESCRIPTION:	Constructor
19*/
20Video :: Video(entry_ref *ref)
21{
22	fMediaFile = 0;
23	fVideoTrack = 0;
24	fBitmap = 0;
25	fVideoThread = 0;
26
27	fMediaFile = new BMediaFile(ref, B_MEDIA_FILE_BIG_BUFFERS);
28	fStatus = fMediaFile->InitCheck();
29	if (fStatus != B_OK)
30		return;
31
32	int32 num_tracks = fMediaFile->CountTracks();
33	for (int32 i=0; i < num_tracks; i++)
34	{
35		BMediaTrack *track = fMediaFile->TrackAt(i);
36		if (track == NULL)
37		{
38			fMediaFile->ReleaseAllTracks();
39			printf("Media file claims to have %ld tracks, cannot find track %ld\n", num_tracks, i);
40			fVideoTrack = 0;
41			return;
42		}
43
44		media_format mf;
45		fStatus = track->EncodedFormat(&mf);
46		if (fStatus == B_OK)
47		{
48			switch (mf.type)
49			{
50				case B_MEDIA_ENCODED_VIDEO:
51				case B_MEDIA_RAW_VIDEO:
52					if (fVideoTrack == 0)
53					{
54						fVideoTrack = track;
55						InitPlayer(&mf);
56					}
57					else
58						printf("Multiple video tracks not supported\n");
59					break;
60				default:
61					fStatus = B_ERROR;
62			}
63		}
64
65		if (fStatus != B_OK)
66			fMediaFile->ReleaseTrack(track);
67	}
68
69	if (fVideoTrack)
70		fStatus = B_OK;
71}
72
73/*	FUNCTION:		Video :: ~Video
74	ARGUMENTS:		n/a
75	RETURN:			n/a
76	DESCRIPTION:	Destructor
77*/
78Video :: ~Video()
79{
80	if (fVideoThread > 0)
81		kill_thread(fVideoThread);
82	delete fMediaFile;
83	delete fBitmap;
84}
85
86/*	FUNCTION:		Video :: InitPlayer
87	ARGUMENTS:		format
88	RETURN:			n/a
89	DESCRIPTION:	Create frame buffer and init decoder
90*/
91void Video :: InitPlayer(media_format *format)
92{
93	BRect frame(0, 0,
94				format->u.encoded_video.output.display.line_width - 1.0f,
95				format->u.encoded_video.output.display.line_count - 1.0f);
96
97	BScreen screen;
98	color_space cs = screen.ColorSpace();
99
100	//	Loop asking the track for a format we can deal with
101	for (;;)
102	{
103		fBitmap = new BBitmap(frame, cs);
104
105		media_format mf, old_mf;
106		memset(&mf, 0, sizeof(media_format));
107		media_raw_video_format  *rvf = &mf.u.raw_video;
108		rvf->last_active = (uint32)(frame.Height() - 1.0f);
109		rvf->orientation = B_VIDEO_TOP_LEFT_RIGHT;
110		rvf->pixel_width_aspect = 1;
111		rvf->pixel_height_aspect = 3;
112		rvf->display.format = cs;
113		rvf->display.line_width = (int32)frame.Width();
114		rvf->display.line_count = (int32)frame.Height();
115		rvf->display.bytes_per_row = fBitmap->BytesPerRow();
116
117		old_mf = mf;
118		fVideoTrack->DecodedFormat(&mf);
119		//	check if match found
120		if (old_mf.u.raw_video.display.format == mf.u.raw_video.display.format)
121			break;
122
123		//	otherwise, change colour space
124		cs = mf.u.raw_video.display.format;
125		delete fBitmap;
126	}
127
128	media_header mh;
129	fVideoTrack->SeekToTime(0);
130	int64 dummy_num_frames;
131	fVideoTrack->ReadFrames((char *)fBitmap->Bits(), &dummy_num_frames, &mh);
132	fVideoTrack->SeekToTime(0);
133}
134
135/*	FUNCTION:		Video :: Start
136	ARGUMENTS:		none
137	RETURN:			n/a
138	DESCRIPTION:	Start playing video
139*/
140void Video :: Start()
141{
142	fVideoThread = spawn_thread(Video::VideoThread, "Video thread", B_NORMAL_PRIORITY, this);
143	if (fVideoThread > 0)
144		resume_thread(fVideoThread);
145}
146
147/*	FUNCTION:		Video :: ShowNextFrame
148	ARGUMENTS:		none
149	RETURN:			status
150	DESCRIPTION:	Read next frame, update texture
151*/
152status_t Video :: ShowNextFrame()
153{
154	status_t 		err;
155	media_header	mh;
156	int64			dummy = 0;
157
158	fBitmap->LockBits();
159	err = fVideoTrack->ReadFrames((char *)fBitmap->Bits(), &dummy, &mh);
160	fBitmap->UnlockBits();
161
162	if (err != B_OK)
163	{
164		//	restart video
165		fVideoTrack->SeekToTime(0);
166		return B_OK;
167	}
168
169	fMediaSource->mOwner->UpdateFrame(fMediaSource);
170	return B_OK;
171}
172
173/*	FUNCTION:		Video :: VideoThread
174	ARGUMENTS:		cookie
175	RETURN:			thread exit status
176	DESCRIPTION:	Video playback thread
177*/
178int32 Video :: VideoThread(void *cookie)
179{
180	Video *video = (Video *) cookie;
181	if (video->fVideoTrack == NULL)
182	{
183		exit_thread(B_ERROR);
184		return B_ERROR;
185	}
186
187	float frames_per_second = (float)video->fVideoTrack->CountFrames() / (float)video->fVideoTrack->Duration() * 1000000.0f;
188	bigtime_t frame_time = (bigtime_t) (1000000.0f / frames_per_second);
189	video->fPerformanceTime = real_time_clock_usecs() + frame_time;
190	status_t err = B_OK;
191	printf("frame_rate = %f\n", frames_per_second);
192
193	while (1)
194	{
195		err = video->ShowNextFrame();
196		bigtime_t zzz = video->fPerformanceTime - real_time_clock_usecs();
197		if (zzz < 0)
198			zzz = 1;
199		video->fPerformanceTime += frame_time;
200		snooze(zzz);
201	}
202	exit_thread(err);
203	return err;
204}
205
206
207
208