Browse Source

Add FFmpeg image file support to the core

jp9000 11 năm trước cách đây
mục cha
commit
32b4d12fe3

+ 7 - 1
libobs/CMakeLists.txt

@@ -16,6 +16,10 @@ find_package(Libavformat REQUIRED)
 include_directories(${LIBAVFORMAT_INCLUDE_DIRS})
 add_definitions(${LIBAVFORMAT_DEFINITIONS})
 
+find_package(Libavcodec REQUIRED)
+include_directories(${LIBAVCODEC_INCLUDE_DIRS})
+add_definitions(${LIBAVCODEC_DEFINITIONS})
+
 add_definitions(-DLIBOBS_EXPORTS)
 
 if(WIN32)
@@ -88,6 +92,7 @@ set(libobs_graphics_SOURCES
 	graphics/matrix4.c
 	graphics/vec3.c
 	graphics/graphics.c
+	graphics/graphics-ffmpeg.c
 	graphics/shader-parser.c
 	graphics/plane.c
 	graphics/effect.c
@@ -238,7 +243,8 @@ target_link_libraries(libobs
 		${LIBSWSCALE_LIBRARIES}
 		${LIBSWRESAMPLE_LIBRARIES}
 		${LIBAVFORMAT_LIBRARIES}
-		${LIBAVUTIL_LIBRARIES})
+		${LIBAVUTIL_LIBRARIES}
+		${LIBAVCODEC_LIBRARIES})
 
 install_obs_core(libobs EXPORT LibObs)
 install_obs_data(libobs ../build/data/libobs libobs)

+ 183 - 0
libobs/graphics/graphics-ffmpeg.c

@@ -0,0 +1,183 @@
+#include "graphics.h"
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libswscale/swscale.h>
+
+struct ffmpeg_image {
+	const char         *file;
+	AVFormatContext    *fmt_ctx;
+	AVCodecContext     *decoder_ctx;
+	AVCodec            *decoder;
+	AVStream           *stream;
+	int                stream_idx;
+
+	int                cx, cy;
+	enum AVPixelFormat format;
+};
+
+static bool ffmpeg_image_open_decoder_context(struct ffmpeg_image *info)
+{
+	int ret = av_find_best_stream(info->fmt_ctx, AVMEDIA_TYPE_VIDEO,
+			-1, 1, NULL, 0);
+	if (ret < 0) {
+		blog(LOG_WARNING, "Couldn't find video stream in file '%s': %s",
+				info->file, av_err2str(ret));
+		return false;
+	}
+
+	info->stream_idx  = ret;
+	info->stream      = info->fmt_ctx->streams[ret];
+	info->decoder_ctx = info->stream->codec;
+	info->decoder     = avcodec_find_decoder(info->decoder_ctx->codec_id);
+
+	if (!info->decoder) {
+		blog(LOG_WARNING, "Failed to find decoder for file '%s'",
+				info->file);
+		return false;
+	}
+
+	ret = avcodec_open2(info->decoder_ctx, info->decoder, NULL);
+	if (ret < 0) {
+		blog(LOG_WARNING, "Failed to open video codec for file '%s': "
+		                  "%s", info->file, av_err2str(ret));
+		return false;
+	}
+
+	return true;
+}
+
+static void ffmpeg_image_free(struct ffmpeg_image *info)
+{
+	avcodec_close(info->decoder_ctx);
+	avformat_close_input(&info->fmt_ctx);
+}
+
+static bool ffmpeg_image_init(struct ffmpeg_image *info, const char *file)
+{
+	int ret;
+
+	memset(info, 0, sizeof(struct ffmpeg_image));
+	info->file       = file;
+	info->stream_idx = -1;
+
+	ret = avformat_open_input(&info->fmt_ctx, file, NULL, NULL);
+	if (ret < 0) {
+		blog(LOG_WARNING, "Failed to open file '%s': %s",
+				info->file, av_err2str(ret));
+		return false;
+	}
+
+	ret = avformat_find_stream_info(info->fmt_ctx, NULL);
+	if (ret < 0) {
+		blog(LOG_WARNING, "Could not find stream info for file '%s':"
+		                  " %s", info->file, av_err2str(ret));
+		goto fail;
+	}
+
+	if (!ffmpeg_image_open_decoder_context(info))
+		goto fail;
+
+	info->cx     = info->decoder_ctx->width;
+	info->cy     = info->decoder_ctx->height;
+	info->format = info->decoder_ctx->pix_fmt;
+	return true;
+
+fail:
+	ffmpeg_image_free(info);
+	return false;
+}
+
+static bool ffmpeg_image_reformat_frame(struct ffmpeg_image *info,
+		AVFrame *frame, uint8_t *out, int linesize)
+{
+	struct SwsContext *sws_ctx = NULL;
+	int               ret      = 0;
+
+	sws_ctx = sws_getContext(info->cx, info->cy, info->format,
+			info->cx, info->cy, AV_PIX_FMT_BGRA,
+			SWS_POINT, NULL, NULL, NULL);
+	if (!sws_ctx) {
+		blog(LOG_WARNING, "Failed to create scale context for '%s'",
+				info->file);
+		return false;
+	}
+
+	ret = sws_scale(sws_ctx, (const uint8_t *const*)frame->data,
+			frame->linesize, 0, info->cy, &out, &linesize);
+	sws_freeContext(sws_ctx);
+
+	if (ret < 0) {
+		blog(LOG_WARNING, "sws_scale failed for '%s': %s",
+				info->file, av_err2str(ret));
+		return false;
+	}
+
+	return true;
+}
+
+static bool ffmpeg_image_decode(struct ffmpeg_image *info, uint8_t *out,
+		int linesize)
+{
+	AVPacket          packet    = {0};
+	bool              success   = false;
+	AVFrame           *frame    = av_frame_alloc();
+	int               got_frame = 0;
+	int               ret;
+
+	if (!frame) {
+		blog(LOG_WARNING, "Failed to create frame data for '%s'",
+				info->file);
+		return false;
+	}
+
+	ret = av_read_frame(info->fmt_ctx, &packet);
+	if (ret < 0) {
+		blog(LOG_WARNING, "Failed to read image frame from '%s': %s",
+				info->file, av_err2str(ret));
+		goto fail;
+	}
+
+	while (!got_frame) {
+		ret = avcodec_decode_video2(info->decoder_ctx, frame,
+				&got_frame, &packet);
+		if (ret < 0) {
+			blog(LOG_WARNING, "Failed to decode frame for '%s': %s",
+					info->file, av_err2str(ret));
+			goto fail;
+		}
+	}
+
+	success = ffmpeg_image_reformat_frame(info, frame, out, linesize);
+
+fail:
+	av_free_packet(&packet);
+	av_frame_free(&frame);
+	return success;
+}
+
+void gs_init_image_deps(void)
+{
+	av_register_all();
+}
+
+void gs_free_image_deps(void)
+{
+}
+
+texture_t gs_create_texture_from_file(const char *file)
+{
+	struct ffmpeg_image image;
+	texture_t           tex = NULL;
+
+	if (ffmpeg_image_init(&image, file)) {
+		uint8_t *data = malloc(image.cx * image.cy * 4);
+		if (ffmpeg_image_decode(&image, data, image.cx * 4))
+			tex = gs_create_texture(image.cx, image.cy, GS_BGRA, 1, 
+					(const uint8_t**)&data, 0);
+
+		ffmpeg_image_free(&image);
+		free(data);
+	}
+	return tex;
+}

+ 6 - 7
libobs/graphics/graphics.c

@@ -36,6 +36,9 @@ static __thread graphics_t thread_graphics = NULL;
 
 #define IMMEDIATE_COUNT 512
 
+extern void gs_init_image_deps(void);
+extern void gs_free_image_deps(void);
+
 bool load_graphics_imports(struct gs_exports *exports, void *module,
 		const char *module_name);
 
@@ -103,6 +106,7 @@ static bool graphics_init(struct graphics_subsystem *graphics)
 
 	graphics->exports.device_leavecontext(graphics->device);
 
+	gs_init_image_deps();
 	return true;
 }
 
@@ -164,6 +168,8 @@ void gs_destroy(graphics_t graphics)
 	if (graphics->module)
 		os_dlclose(graphics->module);
 	bfree(graphics);
+
+	gs_free_image_deps();
 }
 
 void gs_entercontext(graphics_t graphics)
@@ -685,13 +691,6 @@ shader_t gs_create_pixelshader_from_file(const char *file, char **error_string)
 	return shader;
 }
 
-texture_t gs_create_texture_from_file(const char *file)
-{
-	/* TODO */
-	UNUSED_PARAMETER(file);
-	return NULL;
-}
-
 static inline void assign_sprite_rect(float *start, float *end, float size,
 		bool flip)
 {

+ 5 - 4
vs/2013/libobs/libobs.vcxproj

@@ -83,6 +83,7 @@
     <ClCompile Include="..\..\..\libobs\graphics\bounds.c" />
     <ClCompile Include="..\..\..\libobs\graphics\effect-parser.c" />
     <ClCompile Include="..\..\..\libobs\graphics\effect.c" />
+    <ClCompile Include="..\..\..\libobs\graphics\graphics-ffmpeg.c" />
     <ClCompile Include="..\..\..\libobs\graphics\graphics-imports.c" />
     <ClCompile Include="..\..\..\libobs\graphics\graphics.c" />
     <ClCompile Include="..\..\..\libobs\graphics\math-extra.c" />
@@ -213,7 +214,7 @@
     <Link>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>jansson.lib;winmm.lib;avutil.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>jansson.lib;winmm.lib;avutil.lib;avformat.lib;avcodec.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
     </Link>
@@ -234,7 +235,7 @@
     <Link>
       <SubSystem>Windows</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
-      <AdditionalDependencies>jansson.lib;winmm.lib;avutil.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>jansson.lib;winmm.lib;avutil.lib;avformat.lib;avcodec.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
     </Link>
@@ -259,7 +260,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>jansson.lib;winmm.lib;avutil.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>jansson.lib;winmm.lib;avutil.lib;avformat.lib;avcodec.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
     </Link>
@@ -284,7 +285,7 @@
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
       <OptimizeReferences>true</OptimizeReferences>
-      <AdditionalDependencies>jansson.lib;winmm.lib;avutil.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>jansson.lib;winmm.lib;avutil.lib;avformat.lib;avcodec.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
     </Link>

+ 4 - 1
vs/2013/libobs/libobs.vcxproj.filters

@@ -389,5 +389,8 @@
     <ClCompile Include="..\..\..\libobs\media-io\video-matrices.c">
       <Filter>media-io\Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\..\libobs\graphics\graphics-ffmpeg.c">
+      <Filter>graphics\Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
-</Project>
+</Project>