Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

branches\avi_play: MediaContainer::getFrame(int frame_number) works

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