Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/graphics/importer/movie_player.cc @ 6579

Last change on this file since 6579 was 6532, checked in by bensch, 19 years ago

orxonox/trunk: merged branches/movie_play to the trunk. no conflicts, but a minor virtual function BUG

File size: 11.2 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11### File Specific:
12   main-programmer: David Hasenfratz
13   co-programmer:
14*/
15
16
17
18/* this is for debug output. It just says, that all calls to PRINT() belong to the DEBUG_MODULE_MEDIA module
19   For more information refere to https://www.orxonox.net/cgi-bin/trac.cgi/wiki/DebugOutput
20*/
21#define DEBUG_MODULE_MEDIA
22
23
24// include your own header
25#include "movie_player.h"
26
27#include "resource_manager.h"
28
29// header for debug output
30#include "debug.h"
31
32
33MoviePlayer::MoviePlayer(const char* filename)
34{
35  this->init();
36
37  if (filename != NULL)
38  {
39    if(!this->loadMovie(filename))
40      PRINTF(1)("MoviePlayer::loadMovie() failes for %s\n", filename);
41  }
42}
43
44MoviePlayer::MoviePlayer()
45{
46  this->init();
47}
48
49MoviePlayer::~MoviePlayer()
50{
51  delete material;
52  delete model;
53
54  if (glIsTexture(texture))
55    glDeleteTextures(1, &texture);
56
57  // Free the RGB image
58  delete [] buffer;
59  av_free(RGB_frame);
60
61  // Free the frame
62  av_free(frame);
63
64  avcodec_default_free_buffers(codec_context);
65
66  // Close the codec
67  avcodec_close(codec_context);
68
69  // Close the video file
70  av_close_input_file(format_context);
71}
72
73void MoviePlayer::init()
74{
75  // set the class id for the base object
76  this->setClassID(CL_MOVIE_PLAYER, "MoviePlayer");
77
78  status = STOP;
79  timer = 0;
80  frame_number = 0;
81  loading = false;
82
83  material = new Material;
84  material->setDiffuseMap("maps/radialTransparency.png");
85
86  model = new PrimitiveModel(PRIM_PLANE, 10.0);
87
88  LightManager* lightMan = LightManager::getInstance();
89  lightMan->setAmbientColor(.1,.1,.1);
90  (new Light())->setAbsCoor(5.0, 10.0, 40.0);
91  (new Light())->setAbsCoor(-10, -20, -100);
92}
93
94bool MoviePlayer::loadMovie(const char* filename)
95{
96  // register all formats and codecs
97  av_register_all();
98
99  // Open video file
100  if (av_open_input_file(&format_context, ResourceManager::getFullName(filename), NULL, 0, NULL) !=0 )
101  {
102    PRINTF(1)("Could not open %s\n", ResourceManager::getFullName(filename));
103    return false;
104  }
105
106  // Retrieve stream information
107  if (av_find_stream_info(format_context) < 0)
108  {
109    PRINTF(1)("Could not find stream information in %s\n", ResourceManager::getFullName(filename));
110    return false;
111  }
112
113  // Find the first video stream and take it
114  video_stream = av_find_default_stream_index(format_context);
115
116  if(video_stream == -1)
117  {
118    PRINTF(1)("Could not find a video stream in %s\n", ResourceManager::getFullName(filename));
119    return false;
120  }
121
122  // Get a pointer to the codec context for the video stream
123  codec_context = format_context->streams[video_stream]->codec;
124
125  // Find the decoder for the video stream
126  codec = avcodec_find_decoder(codec_context->codec_id);
127  if (codec == NULL)
128  {
129    PRINTF(1)("Could not find codec\n");
130    return false;
131  }
132
133  // Open codec
134  if (avcodec_open(codec_context, codec) < 0)
135  {
136    PRINTF(1)("Could not open codec\n");
137    return false;
138  }
139
140  // Allocate video frame
141  frame = avcodec_alloc_frame();
142  RGB_frame = avcodec_alloc_frame();
143
144  // Determine required buffer size and allocate buffer
145  num_bytes = avpicture_get_size(PIX_FMT_RGB24, codec_context->width, codec_context->height);
146  buffer=new uint8_t[num_bytes];
147
148  // Assign appropriate parts of buffer to image planes in RGB_frame
149  avpicture_fill((AVPicture *)RGB_frame, buffer, PIX_FMT_RGB24, codec_context->width, codec_context->height);
150
151  // data buffer for the texture
152  data = new uint8_t[codec_context->width*codec_context->height*3*sizeof(uint8_t)];
153
154  // Calculate fps
155  fps = av_q2d(format_context->streams[video_stream]->r_frame_rate);
156  // NOTE: fix this fps problem!!
157  if(fps < 0 || fps > 1000)
158    fps = 30;
159
160  // duration
161  duration = format_context->duration / 1000000LL;
162
163  // create texture
164  glGenTextures(1, &texture);
165  glBindTexture(GL_TEXTURE_2D, texture);
166  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
167  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
168  glTexImage2D(GL_TEXTURE_2D,
169              0,
170              GL_RGB,
171              0, 0,
172              0,
173              GL_RGB,
174              GL_UNSIGNED_BYTE,
175              NULL);
176  glBindTexture(GL_TEXTURE_2D, 0);
177
178  loading = true;
179  return true;
180}
181
182void MoviePlayer::getNextFrame()
183{
184  // get next frame
185  if(av_read_frame(format_context, &packet) >= 0)
186  {
187    // Is this a packet from the video stream?
188    if(packet.stream_index == video_stream)
189    {
190      int frame_finished;
191      // Decode video frame
192      avcodec_decode_video(codec_context, frame, &frame_finished,
193                           packet.data, packet.size);
194
195      // Free the packet that was allocated by av_read_frame
196      av_free_packet(&packet);
197     
198      // Did we get a video frame?
199      if(frame_finished)
200      {
201        frame_number++;
202        //PRINTF(0)("frame_number: %i\n", frame_number);
203        // Conversion from YUV to RGB
204        // Most codecs return images in YUV 420 format
205        // (one luminance and two chrominance channels, with the chrominance
206        // channels samples at half the spatial resolution of the luminance channel)
207        img_convert((AVPicture*)RGB_frame, PIX_FMT_RGB24, (AVPicture*)frame,
208                    codec_context->pix_fmt, codec_context->width, codec_context->height);
209
210        for(int i = 0; i < codec_context->height; i++)
211          memcpy(&data[i*codec_context->width*3], ((AVPicture*)RGB_frame)->data[0]+i *
212                 ((AVPicture*)RGB_frame)->linesize[0],
213                 codec_context->width*sizeof(uint8_t)*3);
214
215        glBindTexture(GL_TEXTURE_2D, texture);
216        // update the texture
217        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
218                          codec_context->width, codec_context->height,
219                          GL_RGB, GL_UNSIGNED_BYTE,
220                          data);
221        // build the MipMaps
222        gluBuild2DMipmaps(GL_TEXTURE_2D,
223                        GL_RGB,
224                        codec_context->width,
225                        codec_context->height,
226                        GL_RGB,
227                        GL_UNSIGNED_BYTE,
228                        data);
229        glBindTexture(GL_TEXTURE_2D, 0);
230
231      }
232      else
233      {
234        av_free_packet(&packet);
235        this->getNextFrame();
236      }
237    }
238    else
239    {
240      av_free_packet(&packet);
241      this->getNextFrame();
242    }
243  }
244  else
245    this->stop();
246}
247
248void MoviePlayer::skipFrame(int frames)
249{
250 
251  while(frames != 0)
252  {
253    if(av_read_frame(format_context, &packet) < 0)
254      break;
255    if(packet.stream_index == video_stream)
256    {
257      int frame_finished;
258      // We have to decode the frame to not get ugly fragments
259      avcodec_decode_video(codec_context, frame, &frame_finished,
260                            packet.data, packet.size);
261       
262      // Did we get a video frame?
263      if(frame_finished)
264      {
265        frames--;
266        frame_number++;
267      }
268    }
269    av_free_packet(&packet);
270  }
271 
272  this->getNextFrame();
273
274}
275
276bool MoviePlayer::gotoFrame(int frames)
277{
278  if(!loading)
279  {
280    PRINTF(0)("Load first the media file with loadMovie\n");
281    return false;
282  }
283
284  int err;
285  // seek doesnt work for the first two frames
286  // you will get ugly fragments
287  if(frames < 2)
288  {
289    // go to the begin of the video
290    err = av_seek_frame(format_context, video_stream, 0, AVSEEK_FLAG_BACKWARD);
291    if(err < 0)
292    {
293      PRINTF(1)("Could not seek to frame 0\n");
294      return false;
295    }
296
297    this->frame_number = 0;
298  }
299  else
300  {
301    // seeks to the nearest keyframe
302    // NOTE: there is only about every 5s a keyframe!
303    err = av_seek_frame(format_context, video_stream, frames, AVSEEK_FLAG_BACKWARD);
304    if(err < 0)
305    {
306      PRINTF(1)("Could not seek to frame %i\n", frames);
307      return false;
308    }
309   
310    // go from the keyframe to the exact position
311    codec_context->hurry_up = 1;
312    do {
313      if(av_read_frame(format_context, &packet) < 0)
314      {
315        PRINTF(1)("Could not seek to frame %i\n", frames);
316        return false;
317      }
318
319      if(packet.stream_index == video_stream)
320      {
321        if(packet.pts >= frames-1)
322          break;
323        int frame_finished;
324        avcodec_decode_video(codec_context, frame, &frame_finished, packet.data, packet.size);
325        av_free_packet(&packet);
326      }
327    } while(1);
328    codec_context->hurry_up = 0;
329 
330    this->frame_number = frames;
331  }
332 
333  return true;
334}
335
336void MoviePlayer::start(float start_time)
337{
338  //start_frame = start_time * fps;
339  start_frame = 0;
340
341  if(this->gotoFrame(start_frame))
342  {
343    status = PLAY;
344    timer = 0;
345 
346    this->gotoFrame(start_frame);
347 
348    PRINTF(0)("start\n");
349  }
350}
351
352void MoviePlayer::resume()
353{
354  if(status == PAUSE)
355  {
356    status = PLAY;
357    PRINTF(0)("resume\n");
358  }
359}
360
361void MoviePlayer::pause()
362{
363  if(status == PLAY)
364  {
365    status = PAUSE;
366    PRINTF(0)("pause\n");
367  }
368}
369
370void MoviePlayer::stop()
371{
372  status = STOP;
373
374  PRINTF(0)("stop\n");
375}
376
377void MoviePlayer::tick(float dt)
378{
379  if(status == PLAY)
380  {
381    timer += dt;
382    actual_frame = timer * fps + start_frame;
383    if(actual_frame != frame_number)
384    {
385      if(actual_frame - frame_number == 1)
386        this->getNextFrame();
387      else
388        this->skipFrame(actual_frame - frame_number - 1);
389    }   
390    //PRINTF(0)("frame_number: %i\n", frame_number);
391  }
392}
393
394const void MoviePlayer::draw()
395{
396  material->select();
397  glBindTexture(GL_TEXTURE_2D, texture);
398  model->draw();
399
400  LightManager::getInstance()->draw();
401}
402
403void MoviePlayer::setFPS(float fps)
404{
405  if(fps > 0)
406    this->fps = fps;
407}
408
409float MoviePlayer::getFPS()
410{
411  return this->fps;
412}
413
414const MP_STATUS MoviePlayer::getStatus()
415{
416  return this->status;
417}
418
419void MoviePlayer::printInformation()
420{
421  if(!loading)
422  {
423    PRINTF(0)("Load first the media file with loadMovie\n");
424    return;
425  }
426
427  PRINTF(0)("========================\n");
428  PRINTF(0)("========================\n");
429  PRINTF(0)("=    MEDIACONTAINER    =\n");
430  PRINTF(0)("========================\n");
431  PRINTF(0)("========================\n");
432  PRINTF(0)("=    AVFormatContext   =\n");
433  PRINTF(0)("========================\n");
434  PRINTF(0)("filename: %s\n", format_context->filename);
435  PRINTF(0)("nb_streams: %i\n", format_context->nb_streams);
436  PRINTF(0)("duration: (%02d:%02d:%02d)\n", duration/3600, (duration%3600)/60, duration%60);
437  PRINTF(0)("file_size: %ikb\n", format_context->file_size/1024);
438  PRINTF(0)("bit_rate: %ikb/s\n", format_context->bit_rate/1000);
439  PRINTF(0)("nb_frames: %i\n", format_context->streams[video_stream]->nb_frames);
440  PRINTF(0)("r_frame_rate: %i\n", format_context->streams[video_stream]->r_frame_rate.num);
441  PRINTF(0)("fps: %0.2f\n", fps);
442  PRINTF(0)("========================\n");
443  PRINTF(0)("=    AVCodecContext    =\n");
444  PRINTF(0)("========================\n");
445  PRINTF(0)("width: %i\n", codec_context->width);
446  PRINTF(0)("height: %i\n", codec_context->height);
447  PRINTF(0)("time_base.den: %i\n", codec_context->time_base.den);
448  PRINTF(0)("time_base.num: %i\n", codec_context->time_base.num);
449  PRINTF(0)("========================\n");
450  PRINTF(0)("=       AVCodec        =\n");
451  PRINTF(0)("========================\n");
452  PRINTF(0)("codec name: %s\n", codec->name);
453  PRINTF(0)("========================\n");
454  PRINTF(0)("========================\n");
455}
Note: See TracBrowser for help on using the repository browser.