Add preliminary ffmpeg plugin (still testing)

- Added some code for FFmpeg output that I'm still playing around with.
  Right now I'm just trying to get it to output to file and try to
  understand the FFmpeg/libav APIs.  Hopefully in the future this plugin
  can be used for any sort of output to FFmpeg.

- Fixed a cast warning in audio-io.c with size_t -> uint32_t

- Renamed the 'video_info' and 'audio_info' structures to
  'video_conver_info' and 'audio_convert_info' to better represent their
  actual purpose, and to avoid confusion with 'audio_output_info' and
  'video_output_info' structures.

- Removed a few macros from obs-def.h that were at one point going to be
  used but no longer going to be used (at least for now)
This commit is contained in:
jp9000 2014-01-19 03:16:41 -07:00
parent 8d63845dd4
commit fc8851e9f4
20 changed files with 743 additions and 51 deletions

View File

@ -23,7 +23,7 @@
#include "audio-io.h"
struct audio_input {
struct audio_info format;
struct audio_convert_info conversion;
void (*callback)(void *param, const struct audio_data *data);
void *param;
};
@ -88,13 +88,13 @@ static inline void audio_output_removeline(struct audio_output *audio,
audio_line_destroy_data(line);
}
static inline size_t time_to_frames(audio_t audio, uint64_t offset)
static inline uint32_t time_to_frames(audio_t audio, uint64_t offset)
{
double audio_offset_d = (double)offset;
audio_offset_d /= 1000000000.0;
audio_offset_d *= (double)audio->info.samples_per_sec;
return (size_t)audio_offset_d;
return (uint32_t)audio_offset_d;
}
static inline size_t time_to_bytes(audio_t audio, uint64_t offset)
@ -146,7 +146,7 @@ static inline void mix_audio_line(struct audio_output *audio,
}
static inline void do_audio_output(struct audio_output *audio,
uint64_t timestamp, size_t frames)
uint64_t timestamp, uint32_t frames)
{
struct audio_data data;
data.data = audio->mix_buffer.array;
@ -168,7 +168,7 @@ static void mix_and_output(struct audio_output *audio, uint64_t audio_time,
{
struct audio_line *line = audio->first_line;
uint64_t time_offset = audio_time - prev_time;
size_t frames = time_to_frames(audio, time_offset);
uint32_t frames = time_to_frames(audio, time_offset);
size_t bytes = frames * audio->block_size;
da_resize(audio->mix_buffer, bytes);
@ -231,7 +231,8 @@ static size_t audio_get_input_idx(audio_t video,
return DARRAY_INVALID;
}
void audio_output_connect(audio_t audio, struct audio_info *format,
void audio_output_connect(audio_t audio,
struct audio_convert_info *conversion,
void (*callback)(void *param, const struct audio_data *data),
void *param)
{
@ -243,12 +244,12 @@ void audio_output_connect(audio_t audio, struct audio_info *format,
input.param = param;
/* TODO: conversion */
if (format) {
input.format = *format;
if (conversion) {
input.conversion = *conversion;
} else {
input.format.format = audio->info.format;
input.format.speakers = audio->info.speakers;
input.format.samples_per_sec =
input.conversion.format = audio->info.format;
input.conversion.speakers = audio->info.speakers;
input.conversion.samples_per_sec =
audio->info.samples_per_sec;
}

View File

@ -71,7 +71,7 @@ struct audio_output_info {
uint64_t buffer_ms;
};
struct audio_info {
struct audio_convert_info {
uint32_t samples_per_sec;
enum audio_format format;
enum speaker_layout speakers;
@ -124,7 +124,8 @@ static inline size_t get_audio_size(enum audio_format type,
EXPORT int audio_output_open(audio_t *audio, struct audio_output_info *info);
EXPORT void audio_output_close(audio_t audio);
EXPORT void audio_output_connect(audio_t video, struct audio_info *format,
EXPORT void audio_output_connect(audio_t video,
struct audio_convert_info *conversion,
void (*callback)(void *param, const struct audio_data *data),
void *param);
EXPORT void audio_output_disconnect(audio_t video,

View File

@ -17,9 +17,9 @@
#include "../util/bmem.h"
#include "audio-resampler.h"
#include <libswresample/swresample.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libswresample/swresample.h>
struct audio_resampler {
struct SwrContext *context;

View File

@ -24,8 +24,8 @@
#include "video-io.h"
struct video_input {
struct video_info format;
void (*callback)(void *param, struct video_frame *frame);
struct video_convert_info conversion;
void (*callback)(void *param, const struct video_frame *frame);
void *param;
};
@ -116,7 +116,7 @@ int video_output_open(video_t *video, struct video_output_info *info)
out = bmalloc(sizeof(struct video_output));
memset(out, 0, sizeof(struct video_output));
memcpy(&out->info, info, sizeof(struct video_info));
memcpy(&out->info, info, sizeof(struct video_output_info));
out->frame_time = (uint64_t)(1000000000.0 * (double)info->fps_den /
(double)info->fps_num);
out->initialized = false;
@ -157,7 +157,7 @@ void video_output_close(video_t video)
}
static size_t video_get_input_idx(video_t video,
void (*callback)(void *param, struct video_frame *frame),
void (*callback)(void *param, const struct video_frame *frame),
void *param)
{
for (size_t i = 0; i < video->inputs.num; i++) {
@ -169,8 +169,9 @@ static size_t video_get_input_idx(video_t video,
return DARRAY_INVALID;
}
void video_output_connect(video_t video, struct video_info *format,
void (*callback)(void *param, struct video_frame *frame),
void video_output_connect(video_t video,
struct video_convert_info *conversion,
void (*callback)(void *param, const struct video_frame *frame),
void *param)
{
pthread_mutex_lock(&video->input_mutex);
@ -181,12 +182,18 @@ void video_output_connect(video_t video, struct video_info *format,
input.param = param;
/* TODO: conversion */
if (format) {
input.format = *format;
if (conversion) {
input.conversion = *conversion;
if (input.conversion.width == 0)
input.conversion.width = video->info.width;
if (input.conversion.height == 0)
input.conversion.height = video->info.height;
} else {
input.format.type = video->info.type;
input.format.height = video->info.height;
input.format.width = video->info.width;
input.conversion.format = video->info.format;
input.conversion.width = video->info.width;
input.conversion.height = video->info.height;
input.conversion.row_align = 1;
}
da_push_back(video->inputs, &input);
@ -196,7 +203,7 @@ void video_output_connect(video_t video, struct video_info *format,
}
void video_output_disconnect(video_t video,
void (*callback)(void *param, struct video_frame *frame),
void (*callback)(void *param, const struct video_frame *frame),
void *param)
{
pthread_mutex_lock(&video->input_mutex);

View File

@ -29,7 +29,7 @@ struct video_output;
typedef struct video_output *video_t;
enum video_format {
VIDEO_FORMAT_UNKNOWN,
VIDEO_FORMAT_NONE,
/* planar 420 format */
VIDEO_FORMAT_I420, /* three-plane */
@ -57,18 +57,18 @@ struct video_frame {
struct video_output_info {
const char *name;
enum video_format type;
enum video_format format;
uint32_t fps_num;
uint32_t fps_den;
uint32_t width;
uint32_t height;
};
struct video_info {
enum video_format type;
struct video_convert_info {
enum video_format format;
uint32_t width;
uint32_t height;
uint32_t row_size; /* if any */
uint32_t row_align;
};
#define VIDEO_OUTPUT_SUCCESS 0
@ -78,11 +78,12 @@ struct video_info {
EXPORT int video_output_open(video_t *video, struct video_output_info *info);
EXPORT void video_output_close(video_t video);
EXPORT void video_output_connect(video_t video, struct video_info *format,
void (*callback)(void *param, struct video_frame *frame),
EXPORT void video_output_connect(video_t video,
struct video_convert_info *conversion,
void (*callback)(void *param, const struct video_frame *frame),
void *param);
EXPORT void video_output_disconnect(video_t video,
void (*callback)(void *param, struct video_frame *frame),
void (*callback)(void *param, const struct video_frame *frame),
void *param);
EXPORT const struct video_output_info *video_output_getinfo(video_t video);

View File

@ -31,6 +31,3 @@
#define SOURCE_ASYNC_VIDEO (1<<2) /* Async video (use with SOURCE_VIDEO) */
#define SOURCE_DEFAULT_EFFECT (1<<3) /* Source uses default/filter effect */
#define SOURCE_YUV (1<<4) /* Source is in YUV color space */
#define OUTPUT_VIDEO_ENCODER (1<<0) /* Output requires a video encoder */
#define OUTPUT_AUDIO_ENCODER (1<<1) /* Ouptut requires an audio encoder */

View File

@ -39,6 +39,7 @@
* + myoutput_update
* + myoutput_start
* + myoutput_stop
* + myoutput_active
*
* [and optionally]
* + myoutput_pause

View File

@ -404,7 +404,7 @@ static inline enum convert_type get_convert_type(enum video_format format)
case VIDEO_FORMAT_UYVY:
return CONVERT_422_U;
case VIDEO_FORMAT_UNKNOWN:
case VIDEO_FORMAT_NONE:
case VIDEO_FORMAT_YUVX:
case VIDEO_FORMAT_UYVX:
case VIDEO_FORMAT_RGBA:
@ -427,7 +427,7 @@ static inline bool is_yuv(enum video_format format)
case VIDEO_FORMAT_YUVX:
case VIDEO_FORMAT_UYVX:
return true;
case VIDEO_FORMAT_UNKNOWN:
case VIDEO_FORMAT_NONE:
case VIDEO_FORMAT_RGBA:
case VIDEO_FORMAT_BGRA:
case VIDEO_FORMAT_BGRX:

View File

@ -41,7 +41,7 @@ static inline void make_video_info(struct video_output_info *vi,
struct obs_video_info *ovi)
{
vi->name = "video";
vi->type = ovi->output_format;
vi->format = ovi->output_format;
vi->fps_num = ovi->fps_num;
vi->fps_den = ovi->fps_den;
vi->width = ovi->output_width;
@ -381,7 +381,7 @@ bool obs_get_video_info(struct obs_video_info *ovi)
ovi->base_height = video->base_height;
ovi->output_width = info->width;
ovi->output_height = info->height;
ovi->output_format = info->type;
ovi->output_format = info->format;
ovi->fps_num = info->fps_num;
ovi->fps_den = info->fps_den;

View File

@ -374,9 +374,6 @@ EXPORT bool obs_source_removed(obs_source_t source);
*/
EXPORT uint32_t obs_source_get_output_flags(obs_source_t source);
/** Specifies whether the source can be configured */
EXPORT bool obs_source_hasconfig(obs_source_t source);
/** Updates settings for this source */
EXPORT void obs_source_update(obs_source_t source, const char *settings);

View File

@ -0,0 +1,369 @@
/******************************************************************************
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
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 of the License, or
(at your option) 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include <obs.h>
#include "obs-ffmpeg-output.h"
#define FILENAME_TODO "D:\\test.mp4"
static inline enum AVPixelFormat obs_to_ffmpeg_video_format(
enum video_format format)
{
switch (format) {
case VIDEO_FORMAT_NONE: return AV_PIX_FMT_NONE;
case VIDEO_FORMAT_I420: return AV_PIX_FMT_YUV420P;
case VIDEO_FORMAT_NV12: return AV_PIX_FMT_NV12;
case VIDEO_FORMAT_YVYU: return AV_PIX_FMT_NONE;
case VIDEO_FORMAT_YUY2: return AV_PIX_FMT_YUYV422;
case VIDEO_FORMAT_UYVY: return AV_PIX_FMT_UYVY422;
case VIDEO_FORMAT_YUVX: return AV_PIX_FMT_NONE;
case VIDEO_FORMAT_UYVX: return AV_PIX_FMT_NONE;
case VIDEO_FORMAT_RGBA: return AV_PIX_FMT_RGBA;
case VIDEO_FORMAT_BGRA: return AV_PIX_FMT_BGRA;
case VIDEO_FORMAT_BGRX: return AV_PIX_FMT_BGRA;
}
return AV_PIX_FMT_NONE;
}
static bool new_stream(struct ffmpeg_data *data, AVStream **stream,
AVCodec **codec, enum AVCoecID id)
{
*codec = avcodec_find_encoder(id);
if (!*codec) {
blog(LOG_ERROR, "Couldn't find encoder '%s'",
avcodec_get_name(id));
return false;
}
*stream = avformat_new_stream(data->output, *codec);
if (!*stream) {
blog(LOG_ERROR, "Couldn't create stream for encoder '%s'",
avcodec_get_name(id));
return false;
}
(*stream)->id = data->output->nb_streams-1;
return true;
}
static bool open_video_codec(struct ffmpeg_data *data,
struct obs_video_info *ovi)
{
AVCodecContext *context = data->video->codec;
int ret;
ret = avcodec_open2(context, data->vcodec, NULL);
if (ret < 0) {
blog(LOG_ERROR, "Failed to open video codec: %s",
av_err2str(ret));
return false;
}
data->vframe = av_frame_alloc();
if (!data->vframe) {
blog(LOG_ERROR, "Failed to allocate video frame");
return false;
}
data->vframe->format = context->pix_fmt;
data->vframe->width = context->width;
data->vframe->height = context->height;
ret = avpicture_alloc(&data->dst_picture, context->pix_fmt,
context->width, context->height);
if (ret < 0) {
blog(LOG_ERROR, "Failed to allocate dst_picture: %s",
av_err2str(ret));
return false;
}
if (context->pix_fmt != AV_PIX_FMT_YUV420P) {
ret = avpicture_alloc(&data->src_picture, AV_PIX_FMT_YUV420P,
context->width, context->height);
if (ret < 0) {
blog(LOG_ERROR, "Failed to allocate src_picture: %s",
av_err2str(ret));
return false;
}
}
*((AVPicture*)data->vframe) = data->dst_picture;
return true;
}
static bool create_video_stream(struct ffmpeg_data *data)
{
AVCodecContext *context;
struct obs_video_info ovi;
if (!obs_get_video_info(&ovi)) {
blog(LOG_ERROR, "No active video");
return false;
}
if (!new_stream(data, &data->video, &data->vcodec,
data->output->oformat->video_codec))
return false;
context = data->video->codec;
context->codec_id = data->output->oformat->video_codec;
context->bit_rate = 6000000;
context->width = ovi.output_width;
context->height = ovi.output_height;
context->time_base.num = ovi.fps_den;
context->time_base.den = ovi.fps_num;
context->gop_size = 12;
context->pix_fmt = AV_PIX_FMT_YUV420P;
if (data->output->oformat->flags & AVFMT_GLOBALHEADER)
context->flags |= CODEC_FLAG_GLOBAL_HEADER;
return open_video_codec(data, &ovi);
}
static bool open_audio_codec(struct ffmpeg_data *data,
struct audio_output_info *aoi)
{
AVCodecContext *context = data->audio->codec;
int ret;
data->aframe = av_frame_alloc();
if (!data->aframe) {
blog(LOG_ERROR, "Failed to allocate audio frame");
return false;
}
ret = avcodec_open2(context, data->acodec, NULL);
if (ret < 0) {
blog(LOG_ERROR, "Failed to open audio codec: %s",
av_err2str(ret));
return false;
}
return true;
}
static bool create_audio_stream(struct ffmpeg_data *data)
{
AVCodecContext *context;
struct audio_output_info aoi;
if (!obs_get_audio_info(&aoi)) {
blog(LOG_ERROR, "No active audio");
return false;
}
if (!new_stream(data, &data->audio, &data->acodec,
data->output->oformat->audio_codec))
return false;
context = data->audio->codec;
context->bit_rate = 128000;
context->channels = get_audio_channels(aoi.speakers);
context->sample_rate = aoi.samples_per_sec;
if (data->output->oformat->flags & AVFMT_GLOBALHEADER)
context->flags |= CODEC_FLAG_GLOBAL_HEADER;
return open_audio_codec(data, &aoi);
}
static inline bool init_streams(struct ffmpeg_data *data)
{
AVOutputFormat *format = data->output->oformat;
if (format->video_codec != AV_CODEC_ID_NONE) {
if (!create_video_stream(data))
return false;
}
if (format->audio_codec != AV_CODEC_ID_NONE) {
if (!create_audio_stream(data))
return false;
}
return true;
}
static inline bool open_output_file(struct ffmpeg_data *data)
{
AVOutputFormat *format = data->output->oformat;
int ret;
if ((format->flags & AVFMT_NOFILE) == 0) {
ret = avio_open(&data->output->pb, FILENAME_TODO,
AVIO_FLAG_WRITE);
if (ret < 0) {
blog(LOG_ERROR, "Couldn't open file '%s', %s",
FILENAME_TODO, av_err2str(ret));
return false;
}
}
ret = avformat_write_header(data->output, NULL);
if (ret < 0) {
blog(LOG_ERROR, "Error opening file '%s': %s",
FILENAME_TODO, av_err2str(ret));
}
return true;
}
static void close_video(struct ffmpeg_data *data)
{
avcodec_close(data->video->codec);
av_free(data->src_picture.data[0]);
av_free(data->dst_picture.data[0]);
av_frame_free(&data->vframe);
}
static void close_audio(struct ffmpeg_data *data)
{
avcodec_close(data->audio->codec);
av_free(data->samples[0]);
av_free(data->samples);
av_frame_free(&data->aframe);
}
static void ffmpeg_data_free(struct ffmpeg_data *data)
{
if (data->initialized)
av_write_trailer(data->output);
if (data->video)
close_video(data);
if (data->audio)
close_audio(data);
if ((data->output->oformat->flags & AVFMT_NOFILE) == 0)
avio_close(data->output->pb);
avformat_free_context(data->output);
}
static bool ffmpeg_data_init(struct ffmpeg_data *data)
{
memset(data, 0, sizeof(struct ffmpeg_data));
av_register_all();
/* TODO: settings */
avformat_alloc_output_context2(&data->output, NULL, NULL,
"D:\\test.mp4");
if (!data->output) {
blog(LOG_ERROR, "Couldn't create avformat context");
goto fail;
}
if (!init_streams(data))
goto fail;
if (!open_output_file(data))
goto fail;
data->initialized = true;
return true;
fail:
blog(LOG_ERROR, "ffmpeg_data_init failed");
ffmpeg_data_free(data);
return false;
}
/* ------------------------------------------------------------------------- */
const char *ffmpeg_output_getname(const char *locale)
{
/* TODO: translation */
return "FFmpeg file output";
}
struct ffmpeg_output *ffmpeg_output_create(const char *settings,
obs_output_t output)
{
struct ffmpeg_output *data = bmalloc(sizeof(struct ffmpeg_output));
memset(data, 0, sizeof(struct ffmpeg_output));
data->output = output;
return data;
}
void ffmpeg_output_destroy(struct ffmpeg_output *data)
{
if (data) {
ffmpeg_data_free(&data->ff_data);
bfree(data);
}
}
void ffmpeg_output_update(struct ffmpeg_output *data, const char *settings)
{
}
static void receive_video(void *param, const struct video_frame *frame)
{
}
static void receive_audio(void *param, const struct audio_data *frame)
{
}
bool ffmpeg_output_start(struct ffmpeg_output *data)
{
video_t video = obs_video();
audio_t audio = obs_audio();
if (!video || !audio) {
blog(LOG_ERROR, "ffmpeg_output_start: audio and video must "
"both be active (at least as of this writing)");
return false;
}
if (!ffmpeg_data_init(&data->ff_data))
return false;
struct audio_convert_info aci;
aci.samples_per_sec = 44100;
aci.format = AUDIO_FORMAT_16BIT;
aci.speakers = SPEAKERS_STEREO;
struct video_convert_info vci;
vci.format = VIDEO_FORMAT_I420;
vci.width = 0;
vci.height = 0;
vci.row_align = 1;
video_output_connect(video, &vci, receive_video, data);
audio_output_connect(audio, &aci, receive_audio, data);
data->active = true;
return true;
}
void ffmpeg_output_stop(struct ffmpeg_output *data)
{
if (data->active) {
data->active = false;
video_output_disconnect(obs_video(), receive_video, data);
audio_output_disconnect(obs_audio(), receive_audio, data);
ffmpeg_data_free(&data->ff_data);
}
}
bool ffmpeg_output_active(struct ffmpeg_output *data)
{
return data->active;
}

View File

@ -0,0 +1,62 @@
/******************************************************************************
Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
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 of the License, or
(at your option) 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#pragma once
#include <util/c99defs.h>
#include <media-io/video-io.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
struct ffmpeg_data {
AVStream *video;
AVStream *audio;
AVCodec *acodec;
AVCodec *vcodec;
AVFormatContext *output;
struct SwsContext *swscale;
AVFrame *vframe;
AVPicture src_picture;
AVPicture dst_picture;
AVFrame *aframe;
uint8_t **samples;
bool initialized;
};
struct ffmpeg_output {
obs_output_t output;
volatile bool active;
struct ffmpeg_data ff_data;
};
EXPORT const char *ffmpeg_output_getname(const char *locale);
EXPORT struct ffmpeg_output *ffmpeg_output_create(const char *settings,
obs_output_t output);
EXPORT void ffmpeg_output_destroy(struct ffmpeg_output *data);
EXPORT void ffmpeg_output_update(struct ffmpeg_output *data,
const char *settings);
EXPORT bool ffmpeg_output_start(struct ffmpeg_output *data);
EXPORT void ffmpeg_output_stop(struct ffmpeg_output *data);
EXPORT bool ffmpeg_output_active(struct ffmpeg_output *data);

View File

@ -0,0 +1,14 @@
#include <string.h>
#include <util/c99defs.h>
EXPORT const char *enum_outputs(size_t idx);
static const char *outputs[] = {"obs_ffmpeg"};
const char *enum_outputs(size_t idx)
{
if (idx >= sizeof(outputs)/sizeof(const char*))
return NULL;
return outputs[idx];
}

View File

@ -15,7 +15,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "obs-stream.h"
#include "rtmp-stream.h"
const char *rtmp_stream_getname(const char *locale)
{

View File

@ -40,6 +40,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OBS", "OBS\OBS.vcxproj", "{
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jansson", "..\..\deps\jansson\win32\vs2010\jansson.vcxproj", "{76226D20-1972-4789-A595-EDACC7A76DC3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "obs-ffmpeg", "obs-ffmpeg\obs-ffmpeg.vcxproj", "{36970254-B1E5-4BE6-A561-301B6E7CDCE3}"
ProjectSection(ProjectDependencies) = postProject
{6F1AC2AE-6424-401A-AF9F-A771E6BEE026} = {6F1AC2AE-6424-401A-AF9F-A771E6BEE026}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@ -120,6 +125,14 @@ Global
{76226D20-1972-4789-A595-EDACC7A76DC3}.Release|Win32.Build.0 = Release|Win32
{76226D20-1972-4789-A595-EDACC7A76DC3}.Release|x64.ActiveCfg = Release|x64
{76226D20-1972-4789-A595-EDACC7A76DC3}.Release|x64.Build.0 = Release|x64
{36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Debug|Win32.ActiveCfg = Debug|Win32
{36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Debug|Win32.Build.0 = Debug|Win32
{36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Debug|x64.ActiveCfg = Debug|x64
{36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Debug|x64.Build.0 = Debug|x64
{36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Release|Win32.ActiveCfg = Release|Win32
{36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Release|Win32.Build.0 = Release|Win32
{36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Release|x64.ActiveCfg = Release|x64
{36970254-B1E5-4BE6-A561-301B6E7CDCE3}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{36970254-B1E5-4BE6-A561-301B6E7CDCE3}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>obsffmpeg</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(FFmpegPath);$(IncludePath)</IncludePath>
<LibraryPath>$(FFmpegPath)\lib32;$(FFmpegPath)\libavcodec;$(FFmpegPath)\libavutil;$(FFmpegPath)\libavformat;$(FFmpegPath)\libswresample;$(FFmpegPath)\libswscale;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(FFmpegPath);$(IncludePath)</IncludePath>
<LibraryPath>$(FFmpegPath)\lib64;$(FFmpegPath)\libavcodec;$(FFmpegPath)\libavutil;$(FFmpegPath)\libavformat;$(FFmpegPath)\libswresample;$(FFmpegPath)\libswscale;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(FFmpegPath);$(IncludePath)</IncludePath>
<LibraryPath>$(FFmpegPath)\lib32;$(FFmpegPath)\libavcodec;$(FFmpegPath)\libavutil;$(FFmpegPath)\libavformat;$(FFmpegPath)\libswresample;$(FFmpegPath)\libswscale;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(FFmpegPath);$(IncludePath)</IncludePath>
<LibraryPath>$(FFmpegPath)\lib64;$(FFmpegPath)\libavcodec;$(FFmpegPath)\libavutil;$(FFmpegPath)\libavformat;$(FFmpegPath)\libswresample;$(FFmpegPath)\libswscale;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OBSFFMPEG_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../../libobs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;OBSFFMPEG_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../../libobs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OBSFFMPEG_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../../libobs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;OBSFFMPEG_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>../../../libobs</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>avcodec.lib;avformat.lib;swscale.lib;avutil.lib;libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\plugins\obs-ffmpeg\obs-ffmpeg-output.c" />
<ClCompile Include="..\..\..\plugins\obs-ffmpeg\obs-ffmpeg.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\plugins\obs-ffmpeg\obs-ffmpeg-output.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\plugins\obs-ffmpeg\obs-ffmpeg.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\plugins\obs-ffmpeg\obs-ffmpeg-output.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\plugins\obs-ffmpeg\obs-ffmpeg-output.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -91,7 +91,11 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -106,7 +110,11 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -125,7 +133,11 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/32bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -144,7 +156,11 @@
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>libobs.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
<Command>copy "$(OutDir)$(TargetName)$(TargetExt)" "../../../build/plugins/64bit/$(TargetName)$(TargetExt)"</Command>
</PostBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\..\plugins\obs-outputs\obs-outputs.h" />

View File

@ -15,21 +15,21 @@
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\plugins\obs-outputs\obs-stream.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\plugins\obs-outputs\obs-outputs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\plugins\obs-outputs\obs-x264.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\plugins\obs-outputs\obs-stream.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\plugins\obs-outputs\obs-stream.c">
<ClCompile Include="..\..\..\plugins\obs-outputs\obs-outputs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\plugins\obs-outputs\obs-outputs.c">
<ClCompile Include="..\..\..\plugins\obs-outputs\obs-stream.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\plugins\obs-outputs\obs-x264.c">