Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

branches\avi_play: some fixes

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