|
|
@@ -1,7 +1,10 @@
|
|
|
#include "../stdafx.h"
|
|
|
#include <iostream>
|
|
|
+#include "CSndHandler.h"
|
|
|
#include "CVideoHandler.h"
|
|
|
-#include "SDL.h"
|
|
|
+#include <SDL.h>
|
|
|
+
|
|
|
+#ifdef WIN32
|
|
|
|
|
|
void DLLHandler::Instantiate(const char *filename)
|
|
|
{
|
|
|
@@ -195,4 +198,243 @@ void CBIKHandler::open(std::string name)
|
|
|
// b.PixelFormat:=pf24bit;
|
|
|
// end
|
|
|
//
|
|
|
-//end;
|
|
|
+//end;
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+#include "SDL_Extensions.h"
|
|
|
+
|
|
|
+extern "C" {
|
|
|
+#include <libavformat/avformat.h>
|
|
|
+#include <libswscale/swscale.h>
|
|
|
+}
|
|
|
+
|
|
|
+static const char *protocol_name = "lod";
|
|
|
+
|
|
|
+// Open a pseudo file. Name is something like 'lod:0x56432ab6c43df8fe'
|
|
|
+static int lod_open(URLContext *context, const char *filename, int flags)
|
|
|
+{
|
|
|
+ CVideoPlayer *video;
|
|
|
+
|
|
|
+ // Retrieve pointer to CVideoPlayer object
|
|
|
+ filename += strlen(protocol_name) + 1;
|
|
|
+ video = (CVideoPlayer *)(uintptr_t)strtoull(filename, NULL, 16);
|
|
|
+
|
|
|
+ // TODO: check flags ?
|
|
|
+
|
|
|
+ context->priv_data = video;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int lod_close(URLContext* h)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+// Define a set of functions to read data
|
|
|
+static int lod_read(URLContext *context, unsigned char *buf, int size)
|
|
|
+{
|
|
|
+ CVideoPlayer *video = (CVideoPlayer *)context->priv_data;
|
|
|
+
|
|
|
+ amin(size, video->length - video->offset);
|
|
|
+
|
|
|
+ if (size < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ // TODO: can we avoid that copy ?
|
|
|
+ memcpy(buf, video->data + video->offset, size);
|
|
|
+
|
|
|
+ video->offset += size;
|
|
|
+
|
|
|
+ return size;
|
|
|
+}
|
|
|
+
|
|
|
+static URLProtocol lod_protocol = {
|
|
|
+ protocol_name,
|
|
|
+ lod_open,
|
|
|
+ lod_read,
|
|
|
+ NULL, // no write
|
|
|
+ NULL, // no seek
|
|
|
+ lod_close
|
|
|
+};
|
|
|
+
|
|
|
+CVideoPlayer::CVideoPlayer()
|
|
|
+{
|
|
|
+ format = NULL;
|
|
|
+ frame = NULL;
|
|
|
+ codec = NULL;
|
|
|
+ sws = NULL;
|
|
|
+ overlay = NULL;
|
|
|
+
|
|
|
+ // Register codecs. TODO: May be overkill. Should call a
|
|
|
+ // combination of av_register_input_format() /
|
|
|
+ // av_register_output_format() / av_register_protocol() instead.
|
|
|
+ av_register_all();
|
|
|
+
|
|
|
+ // Register our protocol 'lod' so we can directly read from mmaped memory
|
|
|
+ av_register_protocol(&lod_protocol);
|
|
|
+
|
|
|
+ vidh = new CVidHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "VIDEO.VID"));
|
|
|
+}
|
|
|
+
|
|
|
+bool CVideoPlayer::open(std::string fname, int x, int y)
|
|
|
+{
|
|
|
+ char url[100];
|
|
|
+
|
|
|
+ close();
|
|
|
+
|
|
|
+ data = vidh->extract(fname, length);
|
|
|
+
|
|
|
+ if (data == NULL)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ offset = 0;
|
|
|
+
|
|
|
+ // Create our URL name with the 'lod' protocol as a prefix and a
|
|
|
+ // back pointer to our object. Should be 32 and 64 bits compatible.
|
|
|
+ sprintf(url, "%s:0x%016llx", protocol_name, (unsigned long long)this);
|
|
|
+
|
|
|
+ if (av_open_input_file(&format, url, NULL, 0, NULL)!=0)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Retrieve stream information
|
|
|
+ if (av_find_stream_info(format) < 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Dump information about file onto standard error
|
|
|
+ dump_format(format, 0, url, 0);
|
|
|
+
|
|
|
+ // Find the first video stream
|
|
|
+ stream = -1;
|
|
|
+ for(unsigned int i=0; i<format->nb_streams; i++) {
|
|
|
+ if (format->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
|
|
|
+ stream = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (stream < 0)
|
|
|
+ // No video stream in that file
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Get a pointer to the codec context for the video stream
|
|
|
+ codecContext = format->streams[stream]->codec;
|
|
|
+
|
|
|
+ // Find the decoder for the video stream
|
|
|
+ codec = avcodec_find_decoder(codecContext->codec_id);
|
|
|
+
|
|
|
+ if (codec == NULL) {
|
|
|
+ // Unsupported codec
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Open codec
|
|
|
+ if (avcodec_open(codecContext, codec) <0 ) {
|
|
|
+ // Could not open codec
|
|
|
+ codec = NULL;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Allocate video frame
|
|
|
+ frame = avcodec_alloc_frame();
|
|
|
+
|
|
|
+ // Allocate a place to put our YUV image on that screen
|
|
|
+ overlay = SDL_CreateYUVOverlay(codecContext->width, codecContext->height,
|
|
|
+ SDL_YV12_OVERLAY, screen);
|
|
|
+
|
|
|
+ // Convert the image into YUV format that SDL uses
|
|
|
+ sws = sws_getContext(codecContext->width, codecContext->height,
|
|
|
+ codecContext->pix_fmt, codecContext->width, codecContext->height,
|
|
|
+ PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
|
|
|
+ if (sws == NULL)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ pos.x = x;
|
|
|
+ pos.y = y;
|
|
|
+ pos.w = codecContext->width;
|
|
|
+ pos.h = codecContext->height;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+// Display the next frame. Return false on error/end of file.
|
|
|
+bool CVideoPlayer::nextFrame()
|
|
|
+{
|
|
|
+ AVPacket packet;
|
|
|
+ int frameFinished = 0;
|
|
|
+
|
|
|
+ while(!frameFinished && av_read_frame(format, &packet)>=0) {
|
|
|
+
|
|
|
+ // Is this a packet from the video stream?
|
|
|
+ if (packet.stream_index == stream) {
|
|
|
+ // Decode video frame
|
|
|
+ avcodec_decode_video(codecContext, frame, &frameFinished,
|
|
|
+ packet.data, packet.size);
|
|
|
+
|
|
|
+ // Did we get a video frame?
|
|
|
+ if (frameFinished) {
|
|
|
+ SDL_LockYUVOverlay(overlay);
|
|
|
+
|
|
|
+ AVPicture pict;
|
|
|
+ pict.data[0] = overlay->pixels[0];
|
|
|
+ pict.data[1] = overlay->pixels[2];
|
|
|
+ pict.data[2] = overlay->pixels[1];
|
|
|
+
|
|
|
+ pict.linesize[0] = overlay->pitches[0];
|
|
|
+ pict.linesize[1] = overlay->pitches[2];
|
|
|
+ pict.linesize[2] = overlay->pitches[1];
|
|
|
+
|
|
|
+ sws_scale(sws, frame->data, frame->linesize,
|
|
|
+ 0, codecContext->height, pict.data, pict.linesize);
|
|
|
+
|
|
|
+ SDL_UnlockYUVOverlay(overlay);
|
|
|
+
|
|
|
+ SDL_DisplayYUVOverlay(overlay, &pos);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ av_free_packet(&packet);
|
|
|
+ }
|
|
|
+
|
|
|
+ return frameFinished != 0;
|
|
|
+}
|
|
|
+
|
|
|
+void CVideoPlayer::close()
|
|
|
+{
|
|
|
+ if (sws) {
|
|
|
+ sws_freeContext(sws);
|
|
|
+ sws = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (overlay) {
|
|
|
+ SDL_FreeYUVOverlay(overlay);
|
|
|
+ overlay = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (frame) {
|
|
|
+ av_free(frame);
|
|
|
+ frame = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (codec) {
|
|
|
+ avcodec_close(codecContext);
|
|
|
+ codec = NULL;
|
|
|
+ codecContext = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (format) {
|
|
|
+ av_close_input_file(format);
|
|
|
+ format = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+CVideoPlayer::~CVideoPlayer()
|
|
|
+{
|
|
|
+ close();
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+
|