Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/new_class_id/src/lib/graphics/importer/movie_player.cc @ 9715

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

renamed newclassid to classid and newobjectlist to objectlist

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