Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

some cleanup and fixes

File size: 10.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#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  // Close the codec
65  avcodec_close(codec_context);
66
67  // Close the video file
68  av_close_input_file(format_context);
69}
70
71void MoviePlayer::init()
72{
73  // set the class id for the base object
74  this->setClassID(CL_MOVIE_PLAYER, "MoviePlayer");
75
76  status = STOP;
77  timer = 0;
78  frame_number = 0;
79  loading = false;
80}
81
82bool MoviePlayer::loadMovie(const char* filename)
83{
84  // register all formats and codecs
85  av_register_all();
86
87  // Open video file
88  if (av_open_input_file(&format_context, ResourceManager::getFullName(filename), NULL, 0, NULL) !=0 )
89  {
90    PRINTF(1)("Could not open %s\n", ResourceManager::getFullName(filename));
91    return false;
92  }
93
94  // Retrieve stream information
95  if (av_find_stream_info(format_context) < 0)
96  {
97    PRINTF(1)("Could not find stream information in %s\n", ResourceManager::getFullName(filename));
98    return false;
99  }
100
101  // Find the first video stream and take it
102  video_stream = av_find_default_stream_index(format_context);
103
104  if(video_stream == -1)
105  {
106    PRINTF(1)("Could not find a video stream in %s\n", ResourceManager::getFullName(filename));
107    return false;
108  }
109
110  // Get a pointer to the codec context for the video stream
111  codec_context = format_context->streams[video_stream]->codec;
112
113  // Find the decoder for the video stream
114  codec = avcodec_find_decoder(codec_context->codec_id);
115  if (codec == NULL)
116  {
117    PRINTF(1)("Could not find codec\n");
118    return false;
119  }
120
121  // Open codec
122  if (avcodec_open(codec_context, codec) < 0)
123  {
124    PRINTF(1)("Could not open codec\n");
125    return false;
126  }
127
128  // Allocate video frame
129  frame = avcodec_alloc_frame();
130  RGB_frame = avcodec_alloc_frame();
131
132  // Determine required buffer size and allocate buffer
133  num_bytes = avpicture_get_size(PIX_FMT_RGB24, codec_context->width, codec_context->height);
134  buffer=new uint8_t[num_bytes];
135
136  // Assign appropriate parts of buffer to image planes in RGB_frame
137  avpicture_fill((AVPicture *)RGB_frame, buffer, PIX_FMT_RGB24, codec_context->width, codec_context->height);
138
139  // data buffer for the texture
140  data = new uint8_t[codec_context->width*codec_context->height*3*sizeof(uint8_t)];
141
142  // Calculate fps
143  fps = av_q2d(format_context->streams[video_stream]->r_frame_rate);
144  // NOTE: fix this fps problem!!
145  if(fps < 0 || fps > 1000)
146    fps = 30;
147
148  // duration
149  duration = format_context->duration / 1000000LL;
150
151  // create texture
152  glGenTextures(1, &texture);
153  glBindTexture(GL_TEXTURE_2D, texture);
154  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
155  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
156  glTexImage2D(GL_TEXTURE_2D,
157              0,
158              GL_RGB,
159              0, 0,
160              0,
161              GL_RGB,
162              GL_UNSIGNED_BYTE,
163              NULL);
164  glBindTexture(GL_TEXTURE_2D, 0);
165
166  loading = true;
167  return true;
168}
169
170void MoviePlayer::getNextFrame()
171{
172  // get next frame
173  if(av_read_frame(format_context, &packet) >= 0)
174  {
175    // Is this a packet from the video stream?
176    if(packet.stream_index == video_stream)
177    {
178      int frame_finished;
179      // Decode video frame
180      avcodec_decode_video(codec_context, frame, &frame_finished,
181                           packet.data, packet.size);
182
183      // Free the packet that was allocated by av_read_frame
184      av_free_packet(&packet);
185
186      // Did we get a video frame?
187      if(frame_finished)
188      {
189        frame_number++;
190        //PRINTF(0)("frame_number: %i\n", frame_number);
191        // Conversion from YUV to RGB
192        // Most codecs return images in YUV 420 format
193        // (one luminance and two chrominance channels, with the chrominance
194        // channels samples at half the spatial resolution of the luminance channel)
195        img_convert((AVPicture*)RGB_frame, PIX_FMT_RGB24, (AVPicture*)frame,
196                    codec_context->pix_fmt, codec_context->width, codec_context->height);
197
198        for(int i = 0; i < codec_context->height; i++)
199          memcpy(&data[i*codec_context->width*3], ((AVPicture*)RGB_frame)->data[0]+i *
200                 ((AVPicture*)RGB_frame)->linesize[0],
201                 codec_context->width*sizeof(uint8_t)*3);
202
203        glBindTexture(GL_TEXTURE_2D, texture);
204        // update the texture
205        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
206                          codec_context->width, codec_context->height,
207                          GL_RGB, GL_UNSIGNED_BYTE,
208                          data);
209        // build the MipMaps
210        gluBuild2DMipmaps(GL_TEXTURE_2D,
211                        GL_RGB,
212                        codec_context->width,
213                        codec_context->height,
214                        GL_RGB,
215                        GL_UNSIGNED_BYTE,
216                        data);
217        glBindTexture(GL_TEXTURE_2D, 0);
218
219      }
220      else
221      {
222        av_free_packet(&packet);
223        this->getNextFrame();
224      }
225    }
226    else
227    {
228      av_free_packet(&packet);
229      this->getNextFrame();
230    }
231  }
232  else
233    this->stop();
234}
235
236void MoviePlayer::skipFrame(int frames)
237{
238
239  while(frames != 0)
240  {
241    if(av_read_frame(format_context, &packet) < 0)
242      break;
243    if(packet.stream_index == video_stream)
244    {
245      int frame_finished;
246      // We have to decode the frame to not get ugly fragments
247      avcodec_decode_video(codec_context, frame, &frame_finished,
248                            packet.data, packet.size);
249
250      // Did we get a video frame?
251      if(frame_finished)
252      {
253        frames--;
254        frame_number++;
255      }
256    }
257    av_free_packet(&packet);
258  }
259
260  this->getNextFrame();
261
262}
263
264bool MoviePlayer::gotoFrame(int frames)
265{
266  if(!loading)
267  {
268    PRINTF(0)("Load first the media file with loadMovie\n");
269    return false;
270  }
271
272  int err;
273  // seek doesnt work for the first two frames
274  // you will get ugly fragments
275  if(frames < 2)
276  {
277    // go to the begin of the video
278    err = av_seek_frame(format_context, video_stream, 0, AVSEEK_FLAG_BACKWARD);
279    if(err < 0)
280    {
281      PRINTF(1)("Could not seek to frame 0\n");
282      return false;
283    }
284
285    this->frame_number = 0;
286  }
287  else
288  {
289    // seeks to the nearest keyframe
290    // NOTE: there is only about every 5s a keyframe!
291    err = av_seek_frame(format_context, video_stream, frames, AVSEEK_FLAG_BACKWARD);
292    if(err < 0)
293    {
294      PRINTF(1)("Could not seek to frame %i\n", frames);
295      return false;
296    }
297
298    // go from the keyframe to the exact position
299    codec_context->hurry_up = 1;
300    do {
301      if(av_read_frame(format_context, &packet) < 0)
302      {
303        PRINTF(1)("Could not seek to frame %i\n", frames);
304        return false;
305      }
306
307      if(packet.stream_index == video_stream)
308      {
309        if(packet.pts >= frames-1)
310          break;
311        int frame_finished;
312        avcodec_decode_video(codec_context, frame, &frame_finished, packet.data, packet.size);
313        av_free_packet(&packet);
314      }
315    } while(1);
316    codec_context->hurry_up = 0;
317
318    this->frame_number = frames;
319  }
320
321  return true;
322}
323
324void MoviePlayer::start(float start_time)
325{
326  //start_frame = start_time * fps;
327  start_frame = 0;
328
329  if(this->gotoFrame(start_frame))
330  {
331    status = PLAY;
332    timer = 0;
333  }
334}
335
336void MoviePlayer::resume()
337{
338  if(status == PAUSE)
339    status = PLAY;
340}
341
342void MoviePlayer::pause()
343{
344  if(status == PLAY)
345    status = PAUSE;
346}
347
348void MoviePlayer::stop()
349{
350  status = STOP;
351}
352
353void MoviePlayer::tick(float dt)
354{
355  if(status == PLAY)
356  {
357    timer += dt;
358    actual_frame = (int)(timer * fps + start_frame);
359    if(actual_frame != frame_number)
360    {
361      if(actual_frame - frame_number == 1)
362        this->getNextFrame();
363      else
364        this->skipFrame(actual_frame - frame_number - 1);
365    }
366  }
367}
368
369GLuint MoviePlayer::getTexture()
370{
371  return this->texture;
372}
373
374void MoviePlayer::setFPS(float fps)
375{
376  if(fps > 0)
377    this->fps = fps;
378}
379
380float MoviePlayer::getFPS()
381{
382  return this->fps;
383}
384
385const MP_STATUS MoviePlayer::getStatus()
386{
387  return this->status;
388}
389
390void MoviePlayer::printInformation()
391{
392  if(!loading)
393  {
394    PRINTF(0)("Load first the media file with loadMovie\n");
395    return;
396  }
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", fps);
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.