Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/avi_play/src/lib/graphics/importer/movie_player.cc @ 6382

Last change on this file since 6382 was 6382, checked in by hdavid, 18 years ago

branches\avi_play: removed memory leak

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