Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/avi_play/src/lib/graphics/importer/media_container.cc @ 6325

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

branches\avi_play: the frames are created faster with glTexSubImage2D, implemented custom speed setting

File size: 11.8 KB
RevLine 
[5937]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, Stephan Lienhard
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 "media_container.h"
26
27/* header for debug output */
28#include "debug.h"
29
30
31/**
32 * Default constructor
33 */
[5939]34MediaContainer::MediaContainer(const char* filename)
[5937]35{
[6290]36  this->init();
[5975]37
38  if (filename != NULL)
[5962]39    this->loadMedia(filename);
[6289]40}
[5962]41
[6289]42MediaContainer::MediaContainer()
43{
[6290]44  this->init();
[5937]45}
46
47/**
48 * Default destructor
49 */
50MediaContainer::~MediaContainer()
51{
[6317]52  // delete all textures.
53  while(!this->texture_list.empty())
[6163]54  {
[6317]55    if (glIsTexture(this->texture_list.back()))
56      glDeleteTextures(1, &this->texture_list.back());
57    this->texture_list.pop_back();
[6163]58  }
[6317]59  glDeleteTextures(1, &texture);
[6163]60  SDL_FreeSurface(surface);
[6149]61
[6068]62  // Free the RGB image
63  delete [] buffer;
64  av_free(RGB_frame);
[5937]65
[6013]66  /* Free the frame */
[6003]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);
74
[5937]75}
76
[6290]77void MediaContainer::init()
78{
79  /* set the class id for the base object */
80  this->setClassID(CL_MEDIA_CONTAINER, "MediaContainer");
81
82  /* register all formats and codecs */
83  av_register_all();
84
85  fps = 0;
[6317]86  frame_num = 0;
[6290]87}
88
[6324]89void MediaContainer::gotoFrame(int frame_number)
[5937]90{
[6260]91  // seek doesnt work for the first two frames
92  // you will get ugly fragments
93  if(frame_number < 2)
[6323]94  {
95    // go to the begin of the video
96    av_seek_frame(format_context, video_stream, 0, AVSEEK_FLAG_BACKWARD);
97    frame_num = 0;
98  }
[6260]99  else
[6254]100  {
[6260]101    // seeks to the nearest keyframe
102    // NOTE: there is only about every 5s a keyframe!
103    av_seek_frame(format_context, video_stream, frame_number, AVSEEK_FLAG_BACKWARD);
104   
105    // go from the keyframe to the exact position
106    codec_context->hurry_up = 1;
107    do {
108      av_read_frame(format_context, &packet);
109      if(packet.pts >= frame_number-1)
110        break;
111      int frame_finished;
112      avcodec_decode_video(codec_context, frame, &frame_finished, packet.data, packet.size);
113      av_free_packet(&packet);
114    } while(1);
115    codec_context->hurry_up = 0;
116 
[6323]117    frame_num = frame_number;
[6254]118  }
[5937]119}
120
[6317]121GLuint MediaContainer::getNextFrame()
[5937]122{
[6068]123  /* get next frame */
124  if(av_read_frame(format_context, &packet) >= 0)
125  {
126    //this->printPacketInformation();
[5937]127
[6068]128    /* Is this a packet from the video stream? */
129    if(packet.stream_index == video_stream)
130    {
131      int frame_finished;
132      // Decode video frame
[6163]133      avcodec_decode_video(codec_context, frame, &frame_finished,
134                           packet.data, packet.size);
[6003]135
[6317]136      // Free the packet that was allocated by av_read_frame
137      av_free_packet(&packet);
138     
[6068]139      // Did we get a video frame?
140      if(frame_finished)
141      {
[6317]142        frame_num++;
[6286]143        //PRINTF(1)("frame_number: %i\n", this->getFrameNumber());
[6149]144        // Conversion from YUV to RGB
145        // Most codecs return images in YUV 420 format
146        // (one luminance and two chrominance channels, with the chrominance
147        // channels samples at half the spatial resolution of the luminance channel)
[6163]148        img_convert((AVPicture*)RGB_frame, PIX_FMT_RGB24, (AVPicture*)frame,
149                    codec_context->pix_fmt, codec_context->width, codec_context->height);
[6094]150
151        picture = (AVPicture*)RGB_frame;
[6112]152
153
154        data = 0;
155        data = new uint8_t[codec_context->width*codec_context->height*3*sizeof(uint8_t)];
156        for(int i = 0; i < codec_context->height; i++)
[6260]157          memcpy(&data[i*codec_context->width*3], picture->data[0]+i *
158                 picture->linesize[0],codec_context->width*sizeof(uint8_t)*3);
[6112]159
[6163]160        surface = SDL_CreateRGBSurfaceFrom(data, codec_context->width,
161                                           codec_context->height,24,
162                                           codec_context->width*sizeof(uint8_t)*3,
163#if SDL_BYTEORDER == SDL_LIL_ENDIAN /* OpenGL RGBA masks */
164                                           0x000000FF,
165                                           0x0000FF00,
166                                           0x00FF0000,
167                                           0
168#else
169                                           0xFF000000,
170                                           0x00FF0000,
171                                           0x0000FF00,
172                                           0
173#endif
174                                            );
[6112]175
[6325]176        if(frame_num == 1)
177        {
178          /* Create an OpenGL texture from the surface */
179          glGenTextures(1, &texture);
180          glBindTexture(GL_TEXTURE_2D, texture);
181          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
182          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
183          // create the texture
184          glTexImage2D(GL_TEXTURE_2D,
185                      0,
186                      GL_RGB,
187                      surface->w, surface->h,
188                      0,
189                      GL_RGB,
190                      GL_UNSIGNED_BYTE,
191                      surface->pixels);
192        }
193        else
194          // update the texture
195          glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surface->w, surface->h, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels);
[6317]196        // build the MipMaps
197        gluBuild2DMipmaps(GL_TEXTURE_2D,
198                          GL_RGB,
199                          surface->w,
200                          surface->h,
201                          GL_RGB,
202                          GL_UNSIGNED_BYTE,
203                          surface->pixels);
204        glBindTexture(GL_TEXTURE_2D, 0);
205
206        return texture;
[6068]207      }
208    }
[6317]209    else
210    {
211      av_free_packet(&packet);
212      this->getNextFrame();
213    }
[6068]214  }
215  else
216    return NULL;
217}
[6057]218
[6324]219GLuint MediaContainer::skipFrame(int num_frames)
[6320]220{
[6324]221  frame_num += num_frames;
222 
223  while(num_frames != 0)
224  {
225    if(av_read_frame(format_context, &packet) < 0)
226      break;
227    if(packet.stream_index == video_stream)
228    {
229      int frame_finished;
230      // We have to decode the frame to not get ugly fragments
231      avcodec_decode_video(codec_context, frame, &frame_finished,
232                            packet.data, packet.size);
233       
234      // Did we get a video frame?
235      if(frame_finished)
236        num_frames--;
237    }
238    av_free_packet(&packet);
239  }
240 
241  return this->getNextFrame();
[6320]242}
243
[6317]244vector<GLuint> MediaContainer::getFrameList()
[6163]245{
246
[6317]247  while((texture = this->getNextFrame()) != NULL)
248    texture_list.push_back(texture);
[6163]249
[6317]250  return texture_list;
[6163]251}
252
[6068]253void MediaContainer::saveCurrentFrame()
254{
255  FILE *file;
256  char filename[32];
257  int  y;
[6057]258
[6068]259  // Open file
[6317]260  sprintf(filename, "frame%i.ppm", frame_num);
[6068]261  file = fopen(filename, "wb");
262  if(file == NULL)
[6112]263        return;
[6057]264
[6068]265  // Write header
266  fprintf(file, "P6\n%d %d\n255\n", codec_context->width, codec_context->height);
267  // Write pixel data
268  for(y = 0; y < codec_context->height; y++)
269    fwrite(picture->data[0]+y * picture->linesize[0], 1, codec_context->width*3, file);
270  // Close file
271  fclose(file);
272
273  PRINTF(1)("created file: %s\n", filename);
[6003]274}
275
[5975]276void MediaContainer::loadMedia(const char* filename)
[5937]277{
[5975]278  /* Open video file */
279  if (av_open_input_file(&format_context, filename, NULL, 0, NULL) !=0 )
280    PRINTF(1)("Could not open %s\n", filename);
[5937]281
[6013]282  /* Retrieve stream information */
[6003]283  if (av_find_stream_info(format_context) < 0)
[6112]284    PRINTF(1)("Could not find stream information in %s\n", filename);
[6003]285
286  // Dump information about file onto standard error
287  //dump_format(pFormatCtx, 0, argv[1], false);
288
289  /* Find the first video stream and take it */
290  video_stream = -1;
291  for(int i = 0; i < format_context->nb_streams; i++)
[6013]292  {
293    // NOTE: different code for the 0.4.9-pre1 release of ffmpeg (tardis)
[6112]294    // if(format_context->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO)
[6013]295    if(format_context->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
[6003]296    {
[6013]297      video_stream = i;
[6003]298      break;
299    }
[6013]300  }
[6112]301
[6013]302  if(video_stream == -1)
303    PRINTF(1)("Could not find a video stream in %s\n", filename);
[6003]304
[6013]305  /* Get a pointer to the codec context for the video stream */
306  // NOTE: different code for the 0.4.9-pre1 release of ffmpeg (tardis)
307  // codec_context = &format_context->streams[video_stream]->codec;
[6003]308  codec_context = format_context->streams[video_stream]->codec;
309
[6013]310  /* Find the decoder for the video stream */
[6003]311  codec = avcodec_find_decoder(codec_context->codec_id);
312  if (codec == NULL)
[6013]313    PRINTF(1)("Could not find codec\n");
[6003]314
[6013]315  /* Open codec */
[6003]316  if (avcodec_open(codec_context, codec) < 0)
[6068]317    PRINTF(1)("Could not open codec\n");
[6003]318
[6068]319  // Allocate video frame
320  frame = avcodec_alloc_frame();
[6163]321  RGB_frame = avcodec_alloc_frame();
[6068]322
323  // Determine required buffer size and allocate buffer
324  num_bytes = avpicture_get_size(PIX_FMT_RGB24, codec_context->width, codec_context->height);
325  buffer=new uint8_t[num_bytes];
326
327  // Assign appropriate parts of buffer to image planes in pFrameRGB
[6112]328  avpicture_fill((AVPicture *)RGB_frame, buffer, PIX_FMT_RGB24, codec_context->width, codec_context->height);
[6068]329
[6127]330  // Calculate fps
331  fps = av_q2d(format_context->streams[video_stream]->r_frame_rate);
[6254]332
333  // duration
334  duration = format_context->duration / 1000000LL;
[6317]335
336  frame_num = 0;
[5937]337}
338
339int MediaContainer::getHeight()
340{
[6068]341  return codec_context->height;
[5937]342}
343
344int MediaContainer::getWidth()
345{
[6068]346  return codec_context->width;
[5937]347}
348
[6127]349int MediaContainer::getFrameNumber()
[6094]350{
[6317]351  return frame_num;
[6094]352}
353
[6127]354double MediaContainer::getFPS()
[5937]355{
[6127]356  return this->fps;
[5937]357}
358
[6068]359void MediaContainer::printMediaInformation()
[6057]360{
[6068]361  PRINTF(1)("========================\n");
362  PRINTF(1)("========================\n");
363  PRINTF(1)("=    MEDIACONTAINER    =\n");
364  PRINTF(1)("========================\n");
365  PRINTF(1)("========================\n");
366  PRINTF(1)("=    AVFormatContext   =\n");
367  PRINTF(1)("========================\n");
368  PRINTF(1)("filename: %s\n", format_context->filename);
369  PRINTF(1)("nb_streams: %i\n", format_context->nb_streams);
[6254]370  PRINTF(1)("duration: (%02d:%02d:%02d)\n", duration/3600, (duration%3600)/60, duration%60);
[6068]371  PRINTF(1)("file_size: %ikb\n", format_context->file_size/1024);
372  PRINTF(1)("bit_rate: %ikb/s\n", format_context->bit_rate/1000);
373  PRINTF(1)("nb_frames: %i\n", format_context->streams[video_stream]->nb_frames);
374  PRINTF(1)("r_frame_rate: %i\n", format_context->streams[video_stream]->r_frame_rate.num);
[6260]375  PRINTF(1)("fps: %0.2f\n", av_q2d(format_context->streams[video_stream]->r_frame_rate));
[6068]376  PRINTF(1)("========================\n");
377  PRINTF(1)("=    AVCodecContext    =\n");
378  PRINTF(1)("========================\n");
379  PRINTF(1)("width: %i\n", codec_context->width);
380  PRINTF(1)("height: %i\n", codec_context->height);
[6127]381  PRINTF(1)("time_base.den: %i\n", codec_context->time_base.den);
382  PRINTF(1)("time_base.num: %i\n", codec_context->time_base.num);
[6068]383  PRINTF(1)("========================\n");
384  PRINTF(1)("=       AVCodec        =\n");
385  PRINTF(1)("========================\n");
386  PRINTF(1)("codec name: %s\n", codec->name);
387  PRINTF(1)("========================\n");
388  PRINTF(1)("========================\n");
[6057]389}
390
[6068]391void MediaContainer::printPacketInformation()
[6057]392{
[6068]393  PRINTF(1)("========================\n");
394  PRINTF(1)("========================\n");
395  PRINTF(1)("=       AVPacket       =\n");
396  PRINTF(1)("========================\n");
397  PRINTF(1)("pts: %i\n", packet.pts);
398  PRINTF(1)("dts: %i\n", packet.dts);
399  PRINTF(1)("size: %i\n", packet.size);
400  PRINTF(1)("stream_index: %i\n", packet.stream_index);
401  PRINTF(1)("duration: %i\n", packet.duration);
402  PRINTF(1)("pos: %i\n", packet.pos);
403  PRINTF(1)("========================\n");
404  PRINTF(1)("========================\n");
[6057]405}
Note: See TracBrowser for help on using the repository browser.