2
0
Эх сурвалжийг харах

Basic video player, with no sound, using FFMpeg. Currently plays SMK only.

Frank Zago 16 жил өмнө
parent
commit
dcbf717a07
2 өөрчлөгдсөн 290 нэмэгдсэн , 2 устгасан
  1. 244 2
      hch/CVideoHandler.cpp
  2. 46 0
      hch/CVideoHandler.h

+ 244 - 2
hch/CVideoHandler.cpp

@@ -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
+
+
+

+ 46 - 0
hch/CVideoHandler.h

@@ -1,6 +1,8 @@
 #ifndef __CVIDEOHANDLER_H__
 #define __CVIDEOHANDLER_H__
 
+#ifdef WIN32
+
 #include <stdio.h>
 #ifdef WIN32
 #include <windows.h>
@@ -147,4 +149,48 @@ public:
 	void open(std::string name);
 	void close();
 };
+
+#else
+
+#include <SDL/SDL_video.h>
+
+typedef struct AVFormatContext AVFormatContext;
+typedef struct AVCodecContext AVCodecContext;
+typedef struct AVCodec AVCodec;
+typedef struct AVFrame AVFrame;
+struct SwsContext;
+class CVidHandler;
+
+class CVideoPlayer
+{
+private:
+	int stream;					// stream index in video
+	AVFormatContext *format;
+	AVCodecContext *codecContext; // codec context for stream
+	AVCodec *codec;
+	AVFrame *frame; 
+	struct SwsContext *sws;
+
+	SDL_Overlay *overlay;
+	SDL_Rect pos;				// overlay position
+
+	CVidHandler *vidh;
+
+public:
+	CVideoPlayer();
+	~CVideoPlayer();
+
+	bool init();
+	bool open(std::string fname, int x, int y);
+	void close();
+	bool nextFrame();			// display next frame
+
+	const char *data;			// video buffer
+	int length;					// video size
+	unsigned int offset;		// current data offset
+
+};
+
+#endif
+
 #endif // __CVIDEOHANDLER_H__