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:
parent
8d63845dd4
commit
fc8851e9f4
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -39,6 +39,7 @@
|
||||
* + myoutput_update
|
||||
* + myoutput_start
|
||||
* + myoutput_stop
|
||||
* + myoutput_active
|
||||
*
|
||||
* [and optionally]
|
||||
* + myoutput_pause
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
369
plugins/obs-ffmpeg/obs-ffmpeg-output.c
Normal file
369
plugins/obs-ffmpeg/obs-ffmpeg-output.c
Normal 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;
|
||||
}
|
62
plugins/obs-ffmpeg/obs-ffmpeg-output.h
Normal file
62
plugins/obs-ffmpeg/obs-ffmpeg-output.h
Normal 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);
|
14
plugins/obs-ffmpeg/obs-ffmpeg.c
Normal file
14
plugins/obs-ffmpeg/obs-ffmpeg.c
Normal 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];
|
||||
}
|
@ -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)
|
||||
{
|
@ -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
|
||||
|
183
vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj
Normal file
183
vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj
Normal 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>
|
30
vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj.filters
Normal file
30
vs/2013/obs-ffmpeg/obs-ffmpeg.vcxproj.filters
Normal 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>
|
@ -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" />
|
||||
|
@ -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">
|
||||
|
Loading…
x
Reference in New Issue
Block a user