/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: David Hasenfratz, Stephan Lienhard co-programmer: */ /* this is for debug output. It just says, that all calls to PRINT() belong to the DEBUG_MODULE_MEDIA module For more information refere to https://www.orxonox.net/cgi-bin/trac.cgi/wiki/DebugOutput */ #define DEBUG_MODULE_MEDIA /* include your own header */ #include "media_container.h" /* header for debug output */ #include "debug.h" /** * Default constructor */ MediaContainer::MediaContainer(const char* filename) { // set the class id for the base object this->setClassID(CL_MEDIA_CONTAINER, "MediaContainer"); fps = 0; if (filename != NULL) this->loadMedia(filename); } MediaContainer::MediaContainer() { // set the class id for the base object this->setClassID(CL_MEDIA_CONTAINER, "MediaContainer"); fps = 0; } /** * Default destructor */ MediaContainer::~MediaContainer() { if (glIsTexture(texture)) glDeleteTextures(1, &texture); //SDL_FreeSurface(surface); // Free the RGB image delete [] buffer; av_free(RGB_frame); // Free the frame av_free(frame); // Close the codec avcodec_close(codec_context); // Close the video file av_close_input_file(format_context); } void MediaContainer::loadMedia(const char* filename) { // register all formats and codecs av_register_all(); // Open video file if (av_open_input_file(&format_context, filename, NULL, 0, NULL) !=0 ) PRINTF(1)("Could not open %s\n", filename); // Retrieve stream information if (av_find_stream_info(format_context) < 0) PRINTF(1)("Could not find stream information in %s\n", filename); // Find the first video stream and take it video_stream = av_find_default_stream_index(format_context); if(video_stream == -1) PRINTF(1)("Could not find a video stream in %s\n", filename); // Get a pointer to the codec context for the video stream // NOTE: different code for the 0.4.9-pre1 release of ffmpeg (tardis) // codec_context = &format_context->streams[video_stream]->codec; codec_context = format_context->streams[video_stream]->codec; // Find the decoder for the video stream codec = avcodec_find_decoder(codec_context->codec_id); if (codec == NULL) PRINTF(1)("Could not find codec\n"); // Open codec if (avcodec_open(codec_context, codec) < 0) PRINTF(1)("Could not open codec\n"); // Allocate video frame frame = avcodec_alloc_frame(); RGB_frame = avcodec_alloc_frame(); // Determine required buffer size and allocate buffer num_bytes = avpicture_get_size(PIX_FMT_RGB24, codec_context->width, codec_context->height); buffer=new uint8_t[num_bytes]; // data buffer for the texture data = new uint8_t[codec_context->width*codec_context->height*3*sizeof(uint8_t)]; // Assign appropriate parts of buffer to image planes in RGB_frame avpicture_fill((AVPicture *)RGB_frame, buffer, PIX_FMT_RGB24, codec_context->width, codec_context->height); // Calculate fps fps = av_q2d(format_context->streams[video_stream]->r_frame_rate); // read the frames and save them in a sequence as textures this->loadFrames(); } double MediaContainer::getFPS() { return this->fps; } void MediaContainer::loadFrames() { // empty texture list this->clearLists(); // go to the begin of the video av_seek_frame(format_context, video_stream, 0, AVSEEK_FLAG_BACKWARD); // get all the frames and save them in the sequence while(this->addFrame(this->getNextFrame()) != NULL); } GLuint MediaContainer::getNextFrame() { // get next frame if(av_read_frame(format_context, &packet) >= 0) { // Is this a packet from the video stream? if(packet.stream_index == video_stream) { int frame_finished; // Decode video frame avcodec_decode_video(codec_context, frame, &frame_finished, packet.data, packet.size); // Free the packet that was allocated by av_read_frame av_free_packet(&packet); // Did we get a video frame? if(frame_finished) { // Conversion from YUV to RGB // Most codecs return images in YUV 420 format // (one luminance and two chrominance channels, with the chrominance // channels samples at half the spatial resolution of the luminance channel) img_convert((AVPicture*)RGB_frame, PIX_FMT_RGB24, (AVPicture*)frame, codec_context->pix_fmt, codec_context->width, codec_context->height); for(int i = 0; i < codec_context->height; i++) memcpy(&data[i*codec_context->width*3], ((AVPicture*)RGB_frame)->data[0]+i * ((AVPicture*)RGB_frame)->linesize[0], codec_context->width*sizeof(uint8_t)*3); /*surface = SDL_CreateRGBSurfaceFrom(data, codec_context->width, codec_context->height,24, codec_context->width*sizeof(uint8_t)*3, #if SDL_BYTEORDER == SDL_LIL_ENDIAN // OpenGL RGBA masks 0x000000FF, 0x0000FF00, 0x00FF0000, 0 #else 0xFF000000, 0x00FF0000, 0x0000FF00, 0 #endif ); // Create an OpenGL texture from the surface glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // create the texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, surface->w, surface->h, 0, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels); // build the MipMaps gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, surface->w, surface->h, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels); glBindTexture(GL_TEXTURE_2D, 0); */ // Create an OpenGL texture glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // create the texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, codec_context->width, codec_context->height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); // build the MipMaps gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, codec_context->width, codec_context->height, GL_RGB, GL_UNSIGNED_BYTE, data); glBindTexture(GL_TEXTURE_2D, 0); //avcodec_flush_buffers(codec_context); return texture; } else { av_free_packet(&packet); return this->getNextFrame(); } } else { av_free_packet(&packet); return this->getNextFrame(); } } else return NULL; }