diff sv/videoio/SDL_ffmpeg.cpp @ 125:66af7c1b10d9

(none)
author ivand_qmul
date Mon, 22 Oct 2007 13:59:27 +0000
parents
children 587ad94d6ac2
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sv/videoio/SDL_ffmpeg.cpp	Mon Oct 22 13:59:27 2007 +0000
@@ -0,0 +1,887 @@
+/*******************************************************************************
+*                                                                              *
+*   SDL_ffmpeg is a library for basic multimedia functionality.                *
+*   SDL_ffmpeg is based on ffmpeg.                                             *
+*                                                                              *
+*   Copyright (C) 2007  Arjan Houben                                           *
+*                                                                              *
+*   SDL_ffmpeg is free software: you can redistribute it and/or modify         *
+*   it under the terms of the GNU Lesser General Public License as published   *
+*	by the Free Software Foundation, either version 3 of the License, or any   *
+*   later version.                                                             *
+*                                                                              *
+*   This program is distributed in the hope that it will be useful,            *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of             *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the               *
+*   GNU Lesser General Public License for more details.                        *
+*                                                                              *
+*   You should have received a copy of the GNU Lesser General Public License   *
+*   along with this program.  If not, see <http://www.gnu.org/licenses/>.      *
+*                                                                              *
+*******************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef WIN32
+#include "SDL_ffmpeg.h"
+#include <SDL.h>
+#include <SDL_thread.h>
+#endif
+
+#ifdef __unix__
+#include <SDL/SDL.h>
+#include <SDL/SDL_thread.h>
+#endif
+#ifdef __cplusplus
+}
+#endif
+#include "../../sv/main/MainWindow.h"
+
+//const int SDL_FFMPEG_MAX_BUFFERED_FRAMES = 25;
+//const int SDL_FFMPEG_MAX_BUFFERED_SAMPLES = 512 * 512;
+
+int FFMPEG_init_was_called = 0;
+
+SDL_ffmpegFile* SDL_ffmpegCreateFile() {
+
+    // create SDL_ffmpegFile pointer
+    SDL_ffmpegFile *file = (SDL_ffmpegFile*)malloc( sizeof(SDL_ffmpegFile) );
+    if(!file) return 0;
+	file->_ffmpeg=av_alloc_format_context();//(AVFormatContext*)malloc(sizeof(AVFormatContext));
+    // create a semaphore for every file
+    file->decode = SDL_CreateSemaphore(1);
+
+    // allocate room for VStreams
+    file->vs = (SDL_ffmpegStream**)malloc( sizeof(SDL_ffmpegStream*) * MAX_STREAMS );
+    if(!file->vs) {
+        free( file );
+        return 0;
+    }
+
+    // allocate room for AStreams
+    file->as = (SDL_ffmpegStream**)malloc( sizeof(SDL_ffmpegStream*) * MAX_STREAMS );
+    if(!file->as) {
+        free( file );
+        return 0;
+    }
+
+    // initialize variables with standard values
+    file->audioStream = -1;
+    file->videoStream = -1;
+
+    file->offset = 0;
+    file->videoOffset = 0;
+    file->startTime = 0;
+
+    file->threadID = 0;
+
+    return file;
+}
+
+void SDL_ffmpegFree(SDL_ffmpegFile* file) {
+
+    SDL_ffmpegStopDecoding(file);
+
+    SDL_ffmpegFlush(file);
+
+    free(file);
+}
+
+SDL_ffmpegFile* SDL_ffmpegOpen(const char* filename) {
+
+    
+	// register all codecs
+    if(!FFMPEG_init_was_called) {
+        FFMPEG_init_was_called = 1;
+        av_register_all();
+    }
+	
+    // open new ffmpegFile
+    SDL_ffmpegFile *file = SDL_ffmpegCreateFile();
+    if(!file) return 0;
+
+    // information about format is stored in file->_ffmpeg
+
+    // open the file
+    if(av_open_input_file( (AVFormatContext**)&file->_ffmpeg, filename, 0, 0, 0) != 0) {
+        fprintf(stderr, "could not open \"%s\"\n", filename);
+        free(file);
+        return 0;
+    }
+
+    // retrieve format information
+    if(av_find_stream_info((AVFormatContext *)(file->_ffmpeg)) < 0) {
+        fprintf(stderr, "could not retrieve video stream info");
+        free(file);
+        return 0;
+    }
+
+    // dump info to logfile
+    // dump_format(file->_ffmpeg, 0, filename, 0);
+
+    // find the streams in the file
+    file->VStreams = 0;
+    file->AStreams = 0;
+    file->threadActive = 0;
+
+    // iterate through all the streams and store audio/video streams
+    size_t i;
+    for(i=0; i<((AVFormatContext*)file->_ffmpeg)->nb_streams; i++) {
+
+        if(((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
+
+            // if this is a packet of the correct type we create a new stream
+            SDL_ffmpegStream* stream = (SDL_ffmpegStream*)malloc( sizeof(SDL_ffmpegStream) );
+
+            if(stream) {
+                // we set our stream to zero
+                memset(stream, 0, sizeof(SDL_ffmpegStream));
+
+                // save unique streamid
+                stream->id = i;
+
+                // the timeBase is what we use to calculate from/to pts
+                stream->timeBase = av_q2d(((AVFormatContext*)file->_ffmpeg)->streams[i]->time_base) * 1000;
+
+                // save width, height and pixFmt of our outputframes
+                stream->width = ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->width;
+                stream->height = ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->height;
+                stream->pixFmt = PIX_FMT_RGB24;
+
+                // _ffmpeg holds data about streamcodec
+                stream->_ffmpeg = ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec;
+
+                // get the correct decoder for this stream
+                AVCodec *codec = avcodec_find_decoder(((AVCodecContext*)stream->_ffmpeg)->codec_id);
+
+                if(!codec) {
+                    free(stream);
+                    fprintf(stderr, "could not find codec\n");
+                } else if(avcodec_open(((AVFormatContext*)file->_ffmpeg)->streams[i]->codec, codec) < 0) {
+                    free(stream);
+                    fprintf(stderr, "could not open decoder\n");
+                } else {
+
+                    // copy metadata from AVStream into our stream
+                    stream->frameRate[0] = ((AVFormatContext*)file->_ffmpeg)->streams[i]->time_base.num;
+                    stream->frameRate[1] = ((AVFormatContext*)file->_ffmpeg)->streams[i]->time_base.den;
+                    memcpy(stream->language, ((AVFormatContext*)file->_ffmpeg)->streams[i]->language, 4);
+                    stream->sampleRate = ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->sample_rate;
+                    stream->channels = ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->channels;
+                    memcpy(stream->codecName, ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->codec_name, 32);
+
+                    stream->audio = 0;
+                    stream->size = 0;
+                    stream->imageBuffer = (bufferImage**)calloc( SDL_FFMPEG_MAX_BUFFERED_FRAMES, sizeof(bufferImage*) );
+
+                    file->vs[file->VStreams] = stream;
+                    file->VStreams++;
+
+                    // create semaphore for thread-safe use
+                    stream->sem = SDL_CreateSemaphore(1);
+                }
+            }
+        } else if(((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
+
+            // if this is a packet of the correct type we create a new stream
+            SDL_ffmpegStream* stream = (SDL_ffmpegStream*)malloc( sizeof(SDL_ffmpegStream) );
+
+            if(stream) {
+                // we set our stream to zero
+                memset(stream, 0, sizeof(SDL_ffmpegStream));
+
+                // save unique streamid
+                stream->id = i;
+
+                // the timeBase is what we use to calculate from/to pts
+                stream->timeBase = av_q2d(((AVFormatContext*)file->_ffmpeg)->streams[i]->time_base) * 1000;
+
+                // _ffmpeg holds data about streamcodec
+                stream->_ffmpeg = ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec;
+
+                stream->width = 0;
+                stream->height = 0;
+                stream->pixFmt = PIX_FMT_RGB24;
+
+                // get the correct decoder for this stream
+                AVCodec *codec = avcodec_find_decoder(((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->codec_id);
+
+                if(!codec) {
+                    free( stream );
+                    fprintf(stderr, "could not find codec\n");
+                } else if(avcodec_open(((AVFormatContext*)file->_ffmpeg)->streams[i]->codec, codec) < 0) {
+                    free( stream );
+                    fprintf(stderr, "could not open decoder\n");
+                } else {
+
+                    // copy metadata from AVStream into our stream
+                    stream->frameRate[0] = ((AVFormatContext*)file->_ffmpeg)->streams[i]->time_base.num;
+                    stream->frameRate[1] = ((AVFormatContext*)file->_ffmpeg)->streams[i]->time_base.den;
+                    memcpy(stream->language, ((AVFormatContext*)file->_ffmpeg)->streams[i]->language, 4);
+                    stream->sampleRate = ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->sample_rate;
+                    stream->channels = ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->channels;
+                    memcpy(stream->codecName, ((AVFormatContext*)file->_ffmpeg)->streams[i]->codec->codec_name, 32);
+
+                    stream->audio = (int8_t*)malloc( sizeof(int8_t) * SDL_FFMPEG_MAX_BUFFERED_SAMPLES );
+                    stream->size = 0;
+                    stream->imageBuffer = 0;
+
+                    file->as[file->AStreams] = stream;
+                    file->AStreams++;
+
+                    // create semaphore for thread-safe use
+                    stream->sem = SDL_CreateSemaphore(1);
+                }
+            }
+        }
+    }
+
+    return file;
+}
+
+SDL_Surface* SDL_ffmpegGetVideo(SDL_ffmpegFile* file) {
+
+	MainWindow * MWinsA=MainWindow::instance();
+    if( !SDL_ffmpegValidVideo(file) || file->pause || file->skipVideo) return 0;
+
+    SDL_SemWait(file->vs[file->videoStream]->sem);
+
+    bufferImage *option = 0;
+    int i;
+
+    for(i=0; i<SDL_FFMPEG_MAX_BUFFERED_FRAMES; i++) {
+
+        // if this entry does not exist, continue
+        if(!file->vs[file->videoStream]->imageBuffer[i]) continue;
+		
+
+		int64_t pos=MWinsA->Get_CurAudioTime();
+        // do we have an image that should have been shown?
+        if(file->vs[file->videoStream]->imageBuffer[i]->timestamp <= pos + ((AVFormatContext*)file->_ffmpeg)->start_time/1000) {
+
+            // if this is the first option we find, we simply save it
+            if(!option) {
+
+                option = file->vs[file->videoStream]->imageBuffer[i];
+
+                // set to 0 so we know this position in the buffer is available again
+                file->vs[file->videoStream]->imageBuffer[i] = 0;
+
+            } else {
+
+                // we found a newer possible timestamp, we delete the older one
+                if( option->timestamp < file->vs[file->videoStream]->imageBuffer[i]->timestamp) {
+
+                    // this image is too old, we discard it
+                    SDL_FreeSurface( option->img );
+
+                    // free old option
+                    free( option );
+
+                    // new pointer to position in container
+                    option = file->vs[file->videoStream]->imageBuffer[i];
+
+                    // set to 0 so we know this position in the buffer is available again
+                    file->vs[file->videoStream]->imageBuffer[i] = 0;
+                }
+            }
+        }
+    }
+
+    // if we did not found an option, we exit
+    if(!option) {
+        // release the lock
+        SDL_SemPost(file->vs[file->videoStream]->sem);
+        return 0;
+    }
+
+    // we did found an option, so we return the imagedata
+    return option->img;
+}
+
+int SDL_ffmpegReleaseVideo(SDL_ffmpegFile *file, SDL_Surface *bmp) {
+
+    // if there was no valid video stream, we should not release
+    if( !SDL_ffmpegValidVideo(file) || file->skipVideo) return -1;
+
+    // free surface
+    SDL_FreeSurface(bmp);
+
+    // release semaphore if needed
+    if( !SDL_SemValue(file->vs[file->videoStream]->sem) ) {
+        SDL_SemPost(file->vs[file->videoStream]->sem);
+    }
+
+    return 0;
+}
+
+SDL_ffmpegStream* SDL_ffmpegGetAudioStream(SDL_ffmpegFile *file, int audioID) {
+
+    // check if we have any audiostreams
+    if(!file->AStreams) return 0;
+
+    // check if the requested id is possible
+    if(audioID >= file->AStreams) return 0;
+
+    // return ausiostream linked to audioID
+    return file->as[audioID];
+}
+
+int SDL_ffmpegSelectAudioStream(SDL_ffmpegFile* file, int audioID) {
+
+    // check if we have any audiostreams
+    if(!file->AStreams) return -1;
+
+    // check if the requested id is possible
+    if(audioID >= file->AStreams) return -1;
+
+    // set current audiostream to stream linked to audioID
+    file->audioStream = audioID;
+
+    return 0;
+}
+
+SDL_ffmpegStream* SDL_ffmpegGetVideoStream(SDL_ffmpegFile *file, int videoID) {
+
+    // check if we have any videostreams
+    if(!file->VStreams) return 0;
+
+    // check if the requested id is possible
+    if(videoID >= file->VStreams) return 0;
+
+    // return ausiostream linked to videoID
+    return file->vs[videoID];
+}
+
+int SDL_ffmpegSelectVideoStream(SDL_ffmpegFile* file, int videoID) {
+
+    // check if we have any videostreams
+    if(!file->VStreams) return -1;
+
+    // check if the requested id is possible
+    if(videoID >= file->VStreams) return -1;
+
+    // set current videostream to stream linked to videoID
+    file->videoStream = videoID;
+
+    return 0;
+}
+
+int SDL_ffmpegStartDecoding(SDL_ffmpegFile* file) {
+
+    // start a thread that continues to fill audio/video buffers
+    if(!file->threadID) file->threadID = SDL_CreateThread(SDL_ffmpegDecodeThread, file);
+
+    return 0;
+}
+
+int SDL_ffmpegStopDecoding(SDL_ffmpegFile* file) {
+
+    // stop decode thread
+    file->threadActive = 0;
+    if(file->threadID) SDL_WaitThread(file->threadID, 0);
+
+    // set threadID to zero, so we can check for concurrent threads
+    file->threadID = 0;
+
+    return -1;
+}
+
+int SDL_ffmpegDecodeThread(void* data) {
+	static struct SwsContext *img_convert_ctx;
+    // unpack the void pointer
+    SDL_ffmpegFile* file = (SDL_ffmpegFile*)data;
+
+    // flag this thread as active, used for stopping
+    file->threadActive = 1;
+
+    // create a packet for our data
+    AVPacket pack;
+
+    // reserve some pointers for use in loop
+    AVFrame *inFrame, *inFrameRGB;
+
+    // allocate a frame
+    inFrame = avcodec_alloc_frame();
+
+    // allocate another frame for unknown->RGB conversion
+    inFrameRGB = avcodec_alloc_frame();
+
+    if(SDL_ffmpegValidVideo(file)) {
+        // allocate buffer
+        uint8_t *inVideoBuffer = (uint8_t*)malloc(  avpicture_get_size(file->vs[file->videoStream]->pixFmt,
+                                                        file->vs[file->videoStream]->width,
+                                                        file->vs[file->videoStream]->height) );
+
+        // put buffer into our reserved frame
+        avpicture_fill( (AVPicture*)inFrameRGB,
+                        inVideoBuffer,
+                        file->vs[file->videoStream]->pixFmt,
+                        file->vs[file->videoStream]->width,
+                        file->vs[file->videoStream]->height);
+    }
+
+    // allocate temporary audiobuffer
+    int16_t *samples = (int16_t*)malloc( AVCODEC_MAX_AUDIO_FRAME_SIZE );
+
+    // reserve integer for use in loop
+    int got_frame;
+
+    while(file->threadActive) {
+
+        // read a packet from the file
+        if(av_read_frame((AVFormatContext *)(file->_ffmpeg), &pack) < 0) {
+            // thread is idle
+            SDL_Delay(10);
+            continue;
+        }
+		if (file->skipAudio && pack.stream_index == file->as[file->audioStream]->id){
+			SDL_Delay(1);
+			continue;
+		}
+
+        // we got a packet, lets handle it
+
+        // let's start by entering the video semaphore
+        SDL_SemWait(file->decode);
+
+        // If it's a audio packet from our stream...
+        if( SDL_ffmpegValidAudio(file) && pack.stream_index == file->as[file->audioStream]->id && !file->skipAudio) {
+
+            uint8_t *data = pack.data;
+            int size = pack.size;
+            int len;
+
+            while(size > 0 && file->threadActive) {
+
+                // Decode the packet
+                len = avcodec_decode_audio((AVCodecContext *)(file->as[file->audioStream]->_ffmpeg), samples, &got_frame, data, size);
+
+                // if error, we skip the frame
+                if(len < 0 || !got_frame) {
+                    size = 0;
+                    break;
+                }
+
+                // change pointers
+                data += got_frame;
+                size -= got_frame;
+
+                // if the audiobuffer is full, the thread waits
+                while(  file->as[file->audioStream]->size + got_frame > SDL_FFMPEG_MAX_BUFFERED_SAMPLES &&
+                        file->threadActive) {
+                    SDL_Delay(5);
+                }
+
+                // write an audiopts
+                int64_t audiopts = pack.pts * file->as[file->audioStream]->timeBase;
+
+                // is the audioBuffer is empty
+                if(!file->as[file->audioStream]->size) {
+
+                    // we set a new pts
+                    file->as[file->audioStream]->hardPts = file->as[file->audioStream]->pts = audiopts;
+
+                    // we set totalbytes to zero, as this represents the amount
+                    // of bytes that were played since our last 'hardPts'
+                    file->as[file->audioStream]->totalBytes = 0;
+                }
+
+                // no need to store old samples
+                if(audiopts >= SDL_ffmpegGetPosition(file)) {
+
+                    // enter audio semaphore
+                    SDL_SemWait(file->as[file->audioStream]->sem);
+
+                        // copy data from temporary buffer to streambuffer
+                        memcpy(file->as[file->audioStream]->audio+file->as[file->audioStream]->size, samples, got_frame);
+
+                        // set the new size of the audiobuffer
+                        file->as[file->audioStream]->size += got_frame;
+
+                    // we leave the audio semaphore
+                    SDL_SemPost(file->as[file->audioStream]->sem);
+                }
+            }
+        }
+
+        // If it's a video packet from our video stream...
+        if( SDL_ffmpegValidVideo(file) && pack.stream_index == file->vs[file->videoStream]->id && !file->skipVideo) {
+
+            got_frame = 0;
+
+            // Decode the packet
+            avcodec_decode_video((AVCodecContext *)(file->vs[file->videoStream]->_ffmpeg), inFrame, &got_frame, pack.data, pack.size);
+
+            if(got_frame) {
+
+                // create imagebuffer
+                bufferImage *buf = (bufferImage*)malloc( sizeof(bufferImage) );
+
+                // write timestamp into the buffer
+                buf->timestamp = file->vs[file->videoStream]->timeBase * pack.dts;
+
+                // usefull when dealing with B frames
+                if(pack.dts == AV_NOPTS_VALUE) {
+                    // if we did not get a valid timestamp, we make one up based on the last
+                    // valid timestamp + the duration of a frame
+                    buf->timestamp = file->vs[file->videoStream]->lastTimeStamp + file->vs[file->videoStream]->timeBase;
+                }
+
+                // if new timestamp is from future, we proceed
+			//	if(buf->timestamp >= SDL_ffmpegGetPosition(file)) 
+			//	{
+					if (img_convert_ctx == NULL) {
+							img_convert_ctx = sws_getContext(file->vs[file->videoStream]->width, file->vs[file->videoStream]->height,
+                                                 ((AVCodecContext*)file->vs[file->videoStream]->_ffmpeg)->pix_fmt,
+                                                 file->vs[file->videoStream]->width, file->vs[file->videoStream]->height,
+                                                 file->vs[file->videoStream]->pixFmt,
+                                                 sws_flags, NULL, NULL, NULL);
+							if (img_convert_ctx == NULL) {
+								fprintf(stderr, "Cannot initialize the conversion context\n");
+								exit(1);
+							}
+					}
+				
+				sws_scale(img_convert_ctx, ((AVPicture*)inFrame)->data, ((AVPicture*)inFrame)->linesize,
+                      0, file->vs[file->videoStream]->height, ((AVPicture*)inFrameRGB)->data, ((AVPicture*)inFrameRGB)->linesize);
+				
+                    // we convert whatever type of data we got to RGB24
+                  /* img_convert((AVPicture*)inFrameRGB,
+                        file->vs[file->videoStream]->pixFmt,
+                        (AVPicture*)inFrame,
+                        ((AVCodecContext*)file->vs[file->videoStream]->_ffmpeg)->pix_fmt,
+                        file->vs[file->videoStream]->width,
+                        file->vs[file->videoStream]->height);
+*/
+                    // allocate image room
+                    buf->img = SDL_CreateRGBSurface(SDL_SWSURFACE,
+                        file->vs[file->videoStream]->width,
+                        file->vs[file->videoStream]->height,
+                        24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
+
+                    // copy image data to image room
+                    memcpy(buf->img->pixels, inFrameRGB->data[0],
+                        file->vs[file->videoStream]->width * file->vs[file->videoStream]->height * 3);
+
+                    // we write the lastTimestamp we got
+                    file->vs[file->videoStream]->lastTimeStamp = buf->timestamp;
+
+                    int i;
+                    int again = 1;
+
+                    // keep trying to fit in buffer, until the data was actually placed in the buffer
+                    while(again && file->threadActive) {
+
+                        // we enter the video semaphore
+                        SDL_SemWait(file->vs[file->videoStream]->sem);
+
+                            // loop through all positions in buffer until an empty
+                            // space was found
+                            for(i=0; i<SDL_FFMPEG_MAX_BUFFERED_FRAMES; i++) {
+                                // if this place in the buffer is empty we write our new frame
+                                if(file->vs[file->videoStream]->imageBuffer[i] == 0) {
+                                    file->vs[file->videoStream]->imageBuffer[i] = buf;
+                                    // we placed our image in the buffer, moving on
+                                    again = 0;
+                                    break;
+                                }
+                            }
+
+                        // we leave the video semaphore
+                        SDL_SemPost(file->vs[file->videoStream]->sem);
+
+                        // frames aren't being release every ms, so we can take some
+                        // time before we try and fit our new image again
+                        if(again) SDL_Delay(5);
+                    }
+    //            } 
+				//else {
+    //                // if our decoded frame was too old, we don't bother putting
+    //                // it in our buffer
+    //                free( buf );
+    //            }
+            }
+        }
+        // we leave the decode semaphore
+        SDL_SemPost(file->decode);
+		if ((file->skipAudio)&&(file->delay)) 
+			SDL_Delay(3);
+    }
+    // if we stop this thread, we can release the packet we reserved
+    av_free_packet(&pack);
+
+    return 0;
+}
+
+int SDL_ffmpegSeek(SDL_ffmpegFile* file, int64_t timestamp) {
+
+    // if the seekposition is out of bounds, return
+    if(timestamp >= SDL_ffmpegGetDuration(file)) return -1;
+
+    // start by flushing the buffers
+    SDL_ffmpegFlush(file);
+
+    // we enter the decode semaphore so the decode thread cannot be working on
+    // data we are trying to flush
+    SDL_SemWait(file->decode);
+
+    // if the stream has an offset, add it to the start time
+    int64_t startOffset = 0;
+    if(((AVFormatContext*)file->_ffmpeg)->start_time != AV_NOPTS_VALUE) {
+        // inFormatCtx->start_time is in AV_TIME_BASE fractional seconds
+        startOffset = ((AVFormatContext*)file->_ffmpeg)->start_time;
+    }
+//if (file->skipAudio) startOffset=0;
+    // calculate the final timestamp for the seek action this is in AV_TIME_BASE fractional seconds
+    startOffset += (timestamp * AV_TIME_BASE) / 1000;
+
+    // do the actual seeking, AVSEEK_FLAG_BACKWARD means we jump to the point
+    // closest to the point we want, resulting in an earlier position if the jump
+    // could not go the the exaxt point we wanted
+    if(av_seek_frame((AVFormatContext *)(file->_ffmpeg), -1, startOffset, AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_ANY) >= 0) {
+SDL_Delay(5);
+        // set some values in our file so we now were to start playing
+        file->offset = timestamp;
+        file->startTime = av_gettime()/1000;//SDL_GetTicks();
+
+        // if we have a valid video, we probably have some data we want to flush
+        if( SDL_ffmpegValidVideo(file) && !file->skipVideo) {
+
+            // flushing happens inside the semaphore as not to interfere with the
+            // decoding thread
+            SDL_SemWait(file->vs[file->videoStream]->sem);
+                avcodec_flush_buffers((AVCodecContext *)(file->vs[file->videoStream]->_ffmpeg));
+            SDL_SemPost(file->vs[file->videoStream]->sem);
+        }
+
+        // same goes for audio, if there is data, we flush is
+        if( SDL_ffmpegValidAudio(file)&& !file->skipAudio ) {
+
+            // make sure this is done thread-save, so inside the appropriate
+            // semaphore
+            SDL_SemWait(file->as[file->audioStream]->sem);
+                avcodec_flush_buffers((AVCodecContext *)(file->as[file->audioStream]->_ffmpeg));
+            SDL_SemPost(file->as[file->audioStream]->sem);
+        }
+
+        // then there is our flush call
+        SDL_ffmpegFlush(file);
+
+        // and we are done, lets release the decode semaphore so the decode
+        // thread can move on, filling buffer from our new position
+        SDL_SemPost(file->decode);
+
+        return 0;
+    }
+
+    // if, for some reason, we could not seek, we still should flush our buffers
+    SDL_ffmpegFlush(file);
+
+    // and release our lock on the decodethread
+    SDL_SemPost(file->decode);
+
+    return -1;
+}
+
+int SDL_ffmpegSeekRelative(SDL_ffmpegFile *file, int64_t timestamp) {
+
+    // same thing as normal seek, just take into account the current position
+    return SDL_ffmpegSeek(file, SDL_ffmpegGetPosition(file) + timestamp);
+}
+
+int SDL_ffmpegFlush(SDL_ffmpegFile *file) {
+
+    // if we have a valid audio stream, we flush is
+    if( SDL_ffmpegValidAudio(file)&& !file->skipAudio ) {
+
+        // flush audiobuffer from semaphore, be thread-safe!
+        SDL_SemWait(file->as[file->audioStream]->sem);
+
+            file->as[file->audioStream]->size = 0;
+
+        SDL_SemPost(file->as[file->audioStream]->sem);
+    }
+
+    // if we have a valid video stream, we flush some more
+    if( SDL_ffmpegValidVideo(file) && !file->skipVideo) {
+
+        // flush videobuffer
+        int i;
+
+        // again, be thread safe!
+        SDL_SemWait(file->vs[file->videoStream]->sem);
+
+            // make sure we delete all frames from buffer
+            for(i=0; i<SDL_FFMPEG_MAX_BUFFERED_FRAMES; i++) {
+
+                // if this entry does not exist, continue
+                if(!file->vs[file->videoStream]->imageBuffer[i]) continue;
+
+                // free the actual image data
+                SDL_FreeSurface( file->vs[file->videoStream]->imageBuffer[i]->img );
+
+                // and free the struct containing it
+                free( file->vs[file->videoStream]->imageBuffer[i] );
+
+                // set position in buffer to 0, so we know it is empty
+                file->vs[file->videoStream]->imageBuffer[i] = 0;
+            }
+
+        SDL_SemPost(file->vs[file->videoStream]->sem);
+    }
+
+    return 0;
+}
+
+int8_t* SDL_ffmpegGetAudio(SDL_ffmpegFile *file, int *len) {
+
+    // no valid audio, means no audio to get
+    if( !SDL_ffmpegValidAudio(file) || file->pause||file->skipAudio ) return 0;
+
+    // working on audiobuffer should always be done from semaphore
+    SDL_SemWait(file->as[file->audioStream]->sem);
+
+        // if we ask for more audiodata than we can give, we sent wat we can
+        // actually give, writing the amount of bytes into len
+        if(*len > file->as[file->audioStream]->size) *len = file->as[file->audioStream]->size;
+
+        // decrease the size of our audiobuffer by len
+        file->as[file->audioStream]->size -= *len;
+
+        // len represents the nr of bytes we sent, so we increase the total
+        file->as[file->audioStream]->totalBytes += *len;
+
+        // the videooffset makes sure we are always in sync with the audio
+        // it is actually the difference between the position were we are in the
+        // stream (GetPosition) and were we should be (pts)
+        // we use the same offset when selecting the current videoframe
+        file->videoOffset = SDL_ffmpegGetPosition(file) - file->as[file->audioStream]->pts;
+
+        // we calculate the new pts for our audiodata based on the hardPts
+        // (that is the one we got from ffmpeg) and than calculating how for we
+        // have come since
+        file->as[file->audioStream]->pts = file->as[file->audioStream]->hardPts;
+        // since we use 16bit per sample, we devide totalbytes by 2 before deviding by samplerate
+        file->as[file->audioStream]->pts += ((double)file->as[file->audioStream]->totalBytes / (2 * file->as[file->audioStream]->channels)) / (file->as[file->audioStream]->sampleRate / 1000.0);
+
+        // we return the audiobuffer, notice we are still in the audiosemaphore!
+        // we only leave this by calling SDL_ffmpegReleaseAudio
+        return file->as[file->audioStream]->audio;
+}
+
+int SDL_ffmpegReleaseAudio(SDL_ffmpegFile *file, int len) {
+
+        // no audio, means no releasing
+        if( !SDL_ffmpegValidAudio(file) || file->skipAudio) return -1;
+
+        // this call should be paired with SDL_ffmpegGetAudio, as it provides us
+        // with the correct length so we move the correct amount of data
+        memmove( file->as[file->audioStream]->audio,
+            file->as[file->audioStream]->audio+len,
+            file->as[file->audioStream]->size );
+
+    // work on audiodata is done, so we release the semaphore
+    SDL_SemPost(file->as[file->audioStream]->sem);
+
+    return 0;
+}
+
+int64_t SDL_ffmpegGetPosition(SDL_ffmpegFile *file) {
+    //MainWindow * MWinsA=MainWindow::instance();
+    
+	if (file->skipAudio){
+		return (av_gettime()/1000+ file->offset - file->startTime);
+		//int64_t pos=MWinsA->Get_CurAudioTime();
+		//return (pos + ((AVFormatContext*)file->_ffmpeg)->start_time/1000);//SDL_GetTicks();
+	}
+	else
+		return (av_gettime()/1000+ file->offset - file->startTime);//SDL_GetTicks();
+    // return the current playposition of our file
+    
+}
+
+SDL_AudioSpec* SDL_ffmpegGetAudioSpec(SDL_ffmpegFile *file, int samples, void *callback) {
+
+    // create audio spec
+    SDL_AudioSpec *spec = (SDL_AudioSpec*)malloc( sizeof(SDL_AudioSpec) );
+
+    if(spec) {
+        spec->format = AUDIO_S16SYS;
+        spec->samples = samples;
+        spec->userdata = file;
+        spec->callback = (void (__cdecl *)(void *,Uint8 *,int))(callback);
+        spec->freq = 48000;
+        spec->channels = 2;
+
+        // if we have a valid audiofile, we can use its data to create a
+        // more appropriate audio spec
+        if( SDL_ffmpegValidAudio(file) && !file->skipAudio ) {
+            spec->freq = file->as[file->audioStream]->sampleRate;
+            spec->channels = file->as[file->audioStream]->channels;
+        }
+    }
+
+    return spec;
+}
+
+int64_t SDL_ffmpegGetDuration(SDL_ffmpegFile *file) {
+
+    // returns the duration of the entire file, please note that ffmpeg doesn't
+    // always get this value right! so don't bet your life on it...
+    return ((AVFormatContext*)file->_ffmpeg)->duration / (AV_TIME_BASE / 1000);
+}
+
+int SDL_ffmpegGetVideoSize(SDL_ffmpegFile *file, int *w, int *h) {
+
+    if(!w || !h) return -1;
+
+    // if we have a valid video file selected, we use it
+    // if not, we send default values and return.
+    // by checking the return value you can check if you got a valid size
+    if( SDL_ffmpegValidVideo(file) && !file->skipVideo) {
+        *w = file->vs[file->videoStream]->width;
+        *h = file->vs[file->videoStream]->height;
+        return 0;
+    }
+
+    *w = 320;
+    *h = 240;
+    return -1;
+}
+
+int SDL_ffmpegValidAudio(SDL_ffmpegFile* file) {
+
+    // this function is used to check if we selected a valid audio stream
+    if(file->audioStream < 0 || file->audioStream >= file->AStreams) return 0;
+
+    return 1;
+}
+
+int SDL_ffmpegValidVideo(SDL_ffmpegFile* file) {
+
+    // this function is used to check if we selected a valid video stream
+    if(file->videoStream < 0 || file->videoStream >= file->VStreams) return 0;
+
+    return 1;
+}
+
+int SDL_ffmpegPause(SDL_ffmpegFile *file, int state) {
+
+    // by putting 0 into state, we play the file
+    // this behaviour is analogue to SDL audio
+    file->pause = state;
+
+    if(!file->pause) {
+        file->startTime = av_gettime()/1000;//SDL_GetTicks();
+    }
+
+    return 0;
+}
+
+int SDL_ffmpegGetState(SDL_ffmpegFile *file) {
+    return file->pause;
+}