Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

adapted many classes to the new ClassID System, now comes the hard part… Scripting… then Network… wow this will be so bad :/

File size: 10.9 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 "util/loading/resource_manager.h"
28
29// header for debug output
30#include "debug.h"
31
32NewObjectListDefinition(MoviePlayer);
33
34MoviePlayer::MoviePlayer(const std::string& filename)
35{
36  // set the class id for the base object
37  this->registerObject(this, MoviePlayer::_objectList);
38  status = STOP;
39  timer = 0;
40  frame_number = 0;
41
42  mediaLoaded = false;
43
44  if (!filename.empty())
45    this->loadMovie(filename);
46}
47
48
49MoviePlayer::~MoviePlayer()
50{
51  this->unloadMedia();
52}
53
54void MoviePlayer::unloadMedia()
55{
56  // check whether a movie is already loaded
57  if(!mediaLoaded)
58    return;
59
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);
75
76  status = STOP;
77  timer = 0;
78  frame_number = 0;
79
80  mediaLoaded = false;
81
82}
83
84
85bool MoviePlayer::loadMovie(const std::string& filename)
86{
87  this->unloadMedia();
88
89  if(filename.empty())
90    return false;
91  // check whether file exists
92  if(!ResourceManager::isInDataDir(filename))
93  {
94    PRINTF(1)("Could not find %s\n", filename.c_str());
95    return false;
96  }
97
98  // register all formats and codecs
99  av_register_all();
100
101  // Open video file
102  if (av_open_input_file(&format_context, ResourceManager::getFullName(filename).c_str(), NULL, 0, NULL) !=0 )
103  {
104    PRINTF(1)("Could not open %s\n", ResourceManager::getFullName(filename).c_str());
105    return false;
106  }
107
108  // Retrieve stream information
109  if (av_find_stream_info(format_context) < 0)
110  {
111    PRINTF(1)("Could not find stream information in %s\n", ResourceManager::getFullName(filename).c_str());
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  {
120    PRINTF(1)("Could not find a video stream in %s\n", ResourceManager::getFullName(filename).c_str());
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
180  mediaLoaded = true;
181  return true;
182}
183
184void MoviePlayer::getNextFrame()
185{
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);
196
197      // Free the packet that was allocated by av_read_frame
198      av_free_packet(&packet);
199
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();
248}
249
250void MoviePlayer::skipFrame(int frames)
251{
252
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);
263
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  }
273
274  this->getNextFrame();
275
276}
277
278bool MoviePlayer::gotoFrame(int frames)
279{
280  if(!mediaLoaded)
281  {
282    PRINTF(0)("Load first the media file with loadMovie\n");
283    return false;
284  }
285
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    }
311
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;
331
332    this->frame_number = frames;
333  }
334
335  return true;
336}
337
338void MoviePlayer::start(float start_time)
339{
340  //start_frame = start_time * fps;
341  start_frame = 0;
342
343  if(this->gotoFrame(start_frame))
344  {
345    status = PLAY;
346    timer = 0;
347  }
348}
349
350void MoviePlayer::resume()
351{
352  if(status == PAUSE)
353    status = PLAY;
354}
355
356void MoviePlayer::pause()
357{
358  if(status == PLAY)
359    status = PAUSE;
360}
361
362void MoviePlayer::stop()
363{
364  status = STOP;
365}
366
367void MoviePlayer::tick(float dt)
368{
369  if(status == PLAY)
370  {
371    timer += dt;
372    actual_frame = (int)(timer * fps + start_frame);
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);
379    }
380  }
381}
382
383GLuint MoviePlayer::getTexture()
384{
385  return this->texture;
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
399const MP_STATUS MoviePlayer::getStatus()
400{
401  return this->status;
402}
403
404void MoviePlayer::printInformation()
405{
406  if(!mediaLoaded)
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");
440}
Note: See TracBrowser for help on using the repository browser.