Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9869 was 9869, checked in by bensch, 18 years ago

orxonox/trunk: merged the new_class_id branche back to the trunk.
merged with command:
svn merge https://svn.orxonox.net/orxonox/branches/new_class_id trunk -r9683:HEAD
no conflicts… puh..

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