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