/* 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"); /* register all formats and codecs */ av_register_all(); fps = 0; /* SDL interprets each pixel as a 32-bit number, so our masks must depend on the endianness (byte order) of the machine */ #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; #endif if (filename != NULL) this->loadMedia(filename); } /** * Default destructor */ MediaContainer::~MediaContainer() { // 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); } SDL_Surface* MediaContainer::getFrame(int frame_number) { } SDL_Surface* MediaContainer::getNextFrame() { /* get next frame */ if(av_read_frame(format_context, &packet) >= 0) { //this->printPacketInformation(); /* 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); // Did we get a video frame? if(frame_finished) { PRINTF(1)("frame_number: %i\n", codec_context->frame_number); // 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); picture = (AVPicture*)RGB_frame; data = 0; data = new uint8_t[codec_context->width*codec_context->height*3*sizeof(uint8_t)]; for(int i = 0; i < codec_context->height; i++) memcpy(&data[i*codec_context->width*3], picture->data[0]+i * picture->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, rmask, gmask, bmask, 0); return surface; } } // Free the packet that was allocated by av_read_frame av_free_packet(&packet); } else return NULL; } void MediaContainer::saveCurrentFrame() { FILE *file; char filename[32]; int y; // Open file sprintf(filename, "frame%i.ppm", codec_context->frame_number); file = fopen(filename, "wb"); if(file == NULL) return; // Write header fprintf(file, "P6\n%d %d\n255\n", codec_context->width, codec_context->height); // Write pixel data for(y = 0; y < codec_context->height; y++) fwrite(picture->data[0]+y * picture->linesize[0], 1, codec_context->width*3, file); // Close file fclose(file); PRINTF(1)("created file: %s\n", filename); } void MediaContainer::loadMedia(const char* filename) { /* 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); // Dump information about file onto standard error //dump_format(pFormatCtx, 0, argv[1], false); /* Find the first video stream and take it */ video_stream = -1; for(int i = 0; i < format_context->nb_streams; i++) { // NOTE: different code for the 0.4.9-pre1 release of ffmpeg (tardis) // if(format_context->streams[i]->codec.codec_type == CODEC_TYPE_VIDEO) if(format_context->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) { video_stream = i; break; } } 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]; // Assign appropriate parts of buffer to image planes in pFrameRGB 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); } int MediaContainer::getHeight() { return codec_context->height; } int MediaContainer::getWidth() { return codec_context->width; } int MediaContainer::getFrameNumber() { return codec_context->frame_number; } double MediaContainer::getFPS() { return this->fps; } void MediaContainer::printMediaInformation() { PRINTF(1)("========================\n"); PRINTF(1)("========================\n"); PRINTF(1)("= MEDIACONTAINER =\n"); PRINTF(1)("========================\n"); PRINTF(1)("========================\n"); PRINTF(1)("= AVFormatContext =\n"); PRINTF(1)("========================\n"); PRINTF(1)("filename: %s\n", format_context->filename); PRINTF(1)("nb_streams: %i\n", format_context->nb_streams); PRINTF(1)("duration: %fs\n", format_context->duration/1000000.); PRINTF(1)("file_size: %ikb\n", format_context->file_size/1024); PRINTF(1)("bit_rate: %ikb/s\n", format_context->bit_rate/1000); PRINTF(1)("nb_frames: %i\n", format_context->streams[video_stream]->nb_frames); PRINTF(1)("r_frame_rate: %i\n", format_context->streams[video_stream]->r_frame_rate.num); PRINTF(1)("FPS: %f\n", av_q2d(format_context->streams[video_stream]->r_frame_rate)); PRINTF(1)("========================\n"); PRINTF(1)("= AVCodecContext =\n"); PRINTF(1)("========================\n"); PRINTF(1)("width: %i\n", codec_context->width); PRINTF(1)("height: %i\n", codec_context->height); PRINTF(1)("time_base.den: %i\n", codec_context->time_base.den); PRINTF(1)("time_base.num: %i\n", codec_context->time_base.num); PRINTF(1)("========================\n"); PRINTF(1)("= AVCodec =\n"); PRINTF(1)("========================\n"); PRINTF(1)("codec name: %s\n", codec->name); PRINTF(1)("========================\n"); PRINTF(1)("========================\n"); } void MediaContainer::printPacketInformation() { PRINTF(1)("========================\n"); PRINTF(1)("========================\n"); PRINTF(1)("= AVPacket =\n"); PRINTF(1)("========================\n"); PRINTF(1)("pts: %i\n", packet.pts); PRINTF(1)("dts: %i\n", packet.dts); PRINTF(1)("size: %i\n", packet.size); PRINTF(1)("stream_index: %i\n", packet.stream_index); PRINTF(1)("duration: %i\n", packet.duration); PRINTF(1)("pos: %i\n", packet.pos); PRINTF(1)("========================\n"); PRINTF(1)("========================\n"); }