Implement automatic video scaling (if requested)

Add a scaler interface (defaults to swscale), and if a separate output
wants to use a different scale or format than the default output format,
allow a scaler instance to be created automatically for that output,
which will then receive the new scaled output.
This commit is contained in:
jp9000 2014-02-18 13:37:56 -07:00
parent 1044fa0e86
commit f2d4de3c03
14 changed files with 552 additions and 130 deletions

View File

@ -1,5 +1,9 @@
project(libobs)
find_package(Libswscale REQUIRED)
include_directories(${Libswscale_INCLUDE_DIR})
add_definitions(${Libswscale_DEFINITIONS})
find_package(Libswresample REQUIRED)
include_directories(${Libswresample_INCLUDE_DIR})
add_definitions(${Libswresample_DEFINITIONS})
@ -96,15 +100,19 @@ set(libobs_graphics_HEADERS
set(libobs_mediaio_SOURCES
media-io/video-io.c
media-io/audio-resampler-ffmpeg.c
media-io/audio-io.c
media-io/video-frame.c
media-io/format-conversion.c
media-io/audio-io.c)
media-io/audio-resampler-ffmpeg.c
media-io/video-scaler-ffmpeg.c)
set(libobs_mediaio_HEADERS
media-io/media-io-defs.h
media-io/format-conversion.h
media-io/video-io.h
media-io/audio-io.h
media-io/video-frame.h
media-io/format-conversion.h
media-io/audio-resampler.h
media-io/audio-io.h)
media-io/video-scaler.h)
set(libobs_util_SOURCES
util/base.c
@ -196,10 +204,11 @@ set_target_properties(libobs PROPERTIES
SOVERSION "0")
target_link_libraries(libobs
${libobs_PLATFORM_DEPS}
${Libswscale_LIBRARIES}
${Libswresample_LIBRARIES}
${Libavutil_LIBRARIES})
install_obs_core(libobs)
install_obs_data(libobs ../build/data/libobs libobs)
obs_fixup_install_target(libobs PATH ${Libswresample_LIBRARIES} ${Libavutil_LIBRARIES})
obs_fixup_install_target(libobs PATH ${Libswscale_LIBRARIES} ${Libswresample_LIBRARIES} ${Libavutil_LIBRARIES})

View File

@ -465,7 +465,7 @@ static size_t audio_get_input_idx(audio_t video,
return DARRAY_INVALID;
}
static inline void audio_input_init(struct audio_input *input,
static inline bool audio_input_init(struct audio_input *input,
struct audio_output *audio)
{
if (input->conversion.format != audio->info.format ||
@ -484,16 +484,25 @@ static inline void audio_input_init(struct audio_input *input,
};
input->resampler = audio_resampler_create(&to, &from);
if (!input->resampler) {
blog(LOG_WARNING, "audio_input_init: Failed to "
"create resampler");
return false;
}
} else {
input->resampler = NULL;
}
return true;
}
void audio_output_connect(audio_t audio,
bool audio_output_connect(audio_t audio,
struct audio_convert_info *conversion,
void (*callback)(void *param, const struct audio_data *data),
void *param)
{
bool success = false;
pthread_mutex_lock(&audio->input_mutex);
if (audio_get_input_idx(audio, callback, param) == DARRAY_INVALID) {
@ -510,11 +519,14 @@ void audio_output_connect(audio_t audio,
audio->info.samples_per_sec;
}
audio_input_init(&input, audio);
da_push_back(audio->inputs, &input);
success = audio_input_init(&input, audio);
if (success)
da_push_back(audio->inputs, &input);
}
pthread_mutex_unlock(&audio->input_mutex);
return success;
}
void audio_output_disconnect(audio_t audio,

View File

@ -164,7 +164,7 @@ 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,
EXPORT bool audio_output_connect(audio_t video,
struct audio_convert_info *conversion,
void (*callback)(void *param, const struct audio_data *data),
void *param);

View File

@ -0,0 +1,86 @@
/******************************************************************************
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 "video-frame.h"
#define ALIGN_SIZE(size, align) \
size = (((size)+(align-1)) & (~(align-1)))
/* messy code alarm */
void video_frame_init(struct video_frame *frame, enum video_format format,
uint32_t width, uint32_t height)
{
size_t size;
size_t offsets[MAX_AV_PLANES];
int alignment = base_get_alignment();
memset(frame, 0, sizeof(struct video_frame));
memset(offsets, 0, sizeof(offsets));
switch (format) {
case VIDEO_FORMAT_NONE:
return;
case VIDEO_FORMAT_I420:
size = width * height;
ALIGN_SIZE(size, alignment);
offsets[0] = size;
size += (width/2) * (height/2);
ALIGN_SIZE(size, alignment);
offsets[1] = size;
size += (width/2) * (height/2);
ALIGN_SIZE(size, alignment);
frame->data[0] = bmalloc(size);
frame->data[1] = (uint8_t*)frame->data[0] + offsets[0];
frame->data[2] = (uint8_t*)frame->data[0] + offsets[1];
frame->linesize[0] = width;
frame->linesize[1] = width/2;
frame->linesize[2] = width/2;
break;
case VIDEO_FORMAT_NV12:
size = width * height;
ALIGN_SIZE(size, alignment);
offsets[0] = size;
size += (width/2) * (height/2) * 2;
ALIGN_SIZE(size, alignment);
frame->data[0] = bmalloc(size);
frame->data[1] = (uint8_t*)frame->data[0] + offsets[0];
frame->linesize[0] = width;
frame->linesize[1] = width;
break;
case VIDEO_FORMAT_YVYU:
case VIDEO_FORMAT_YUY2:
case VIDEO_FORMAT_UYVY:
size = width * height * 2;
ALIGN_SIZE(size, alignment);
frame->data[0] = bmalloc(size);
frame->linesize[0] = width*2;
break;
case VIDEO_FORMAT_RGBA:
case VIDEO_FORMAT_BGRA:
case VIDEO_FORMAT_BGRX:
size = width * height * 4;
ALIGN_SIZE(size, alignment);
frame->data[0] = bmalloc(size);
frame->linesize[0] = width*4;
break;
}
}

View File

@ -0,0 +1,53 @@
/******************************************************************************
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 "../util/bmem.h"
#include "video-io.h"
struct video_frame {
uint8_t *data[MAX_AV_PLANES];
uint32_t linesize[MAX_AV_PLANES];
};
EXPORT void video_frame_init(struct video_frame *frame,
enum video_format format, uint32_t width, uint32_t height);
static inline void video_frame_free(struct video_frame *frame)
{
if (frame) {
bfree(frame->data[0]);
memset(frame, 0, sizeof(struct video_frame));
}
}
static inline struct video_frame *video_frame_create(
enum video_format format, uint32_t width, uint32_t height)
{
struct video_frame *frame;
frame = (struct video_frame*)bzalloc(sizeof(struct video_frame));
video_frame_init(frame, format, width, height);
return frame;
}
static inline void video_frame_destroy(struct video_frame *frame)
{
if (frame) {
bfree(frame->data[0]);
bfree(frame);
}
}

View File

@ -23,13 +23,28 @@
#include "format-conversion.h"
#include "video-io.h"
#include "video-frame.h"
#include "video-scaler.h"
#define MAX_CONVERT_BUFFERS 3
struct video_input {
struct video_convert_info conversion;
void (*callback)(void *param, const struct video_frame *frame);
struct video_scale_info conversion;
video_scaler_t scaler;
struct video_frame frame[MAX_CONVERT_BUFFERS];
int cur_frame;
void (*callback)(void *param, const struct video_data *frame);
void *param;
};
static inline void video_input_free(struct video_input *input)
{
for (size_t i = 0; i < MAX_CONVERT_BUFFERS; i++)
video_frame_free(&input->frame[i]);
video_scaler_destroy(input->scaler);
}
struct video_output {
struct video_output_info info;
@ -37,8 +52,8 @@ struct video_output {
pthread_mutex_t data_mutex;
event_t stop_event;
struct video_frame cur_frame;
struct video_frame next_frame;
struct video_data cur_frame;
struct video_data next_frame;
bool new_frame;
event_t update_event;
@ -61,6 +76,34 @@ static inline void video_swapframes(struct video_output *video)
}
}
static inline bool scale_video_output(struct video_input *input,
struct video_data *data)
{
bool success = true;
if (input->scaler) {
struct video_frame *frame;
if (++input->cur_frame == MAX_CONVERT_BUFFERS)
input->cur_frame = 0;
frame = &input->frame[input->cur_frame];
success = video_scaler_scale(input->scaler,
frame->data, frame->linesize,
data->data, data->linesize);
if (success) {
for (size_t i = 0; i < MAX_AV_PLANES; i++) {
data->data[i] = frame->data[i];
data->linesize[i] = frame->linesize[i];
}
}
}
return success;
}
static inline void video_output_cur_frame(struct video_output *video)
{
if (!video->cur_frame.data[0])
@ -68,10 +111,10 @@ static inline void video_output_cur_frame(struct video_output *video)
pthread_mutex_lock(&video->input_mutex);
/* TODO: conversion */
for (size_t i = 0; i < video->inputs.num; i++) {
struct video_input *input = video->inputs.array+i;
input->callback(input->param, &video->cur_frame);
if (scale_video_output(input, &video->cur_frame))
input->callback(input->param, &video->cur_frame);
}
pthread_mutex_unlock(&video->input_mutex);
@ -151,7 +194,10 @@ void video_output_close(video_t video)
video_output_stop(video);
for (size_t i = 0; i < video->inputs.num; i++)
video_input_free(&video->inputs.array[i]);
da_free(video->inputs);
event_destroy(&video->update_event);
event_destroy(&video->stop_event);
pthread_mutex_destroy(&video->data_mutex);
@ -160,7 +206,7 @@ void video_output_close(video_t video)
}
static size_t video_get_input_idx(video_t video,
void (*callback)(void *param, const struct video_frame *frame),
void (*callback)(void *param, const struct video_data *frame),
void *param)
{
for (size_t i = 0; i < video->inputs.num; i++) {
@ -172,47 +218,92 @@ static size_t video_get_input_idx(video_t video,
return DARRAY_INVALID;
}
void video_output_connect(video_t video,
struct video_convert_info *conversion,
void (*callback)(void *param, const struct video_frame *frame),
static inline bool video_input_init(struct video_input *input,
struct video_output *video)
{
if (input->conversion.width != video->info.width ||
input->conversion.height != video->info.height ||
input->conversion.format != video->info.format) {
struct video_scale_info from = {
.format = video->info.format,
.width = video->info.width,
.height = video->info.height,
};
int ret = video_scaler_create(&input->scaler,
&input->conversion, &from,
VIDEO_SCALE_FAST_BILINEAR);
if (ret != VIDEO_SCALER_SUCCESS) {
if (ret == VIDEO_SCALER_BAD_CONVERSION)
blog(LOG_WARNING, "video_input_init: Bad "
"scale conversion type");
else
blog(LOG_WARNING, "video_input_init: Failed to "
"create scaler");
return false;
}
for (size_t i = 0; i < MAX_CONVERT_BUFFERS; i++)
video_frame_init(&input->frame[i],
input->conversion.format,
input->conversion.width,
input->conversion.height);
}
return true;
}
bool video_output_connect(video_t video,
struct video_scale_info *conversion,
void (*callback)(void *param, const struct video_data *frame),
void *param)
{
bool success = false;
pthread_mutex_lock(&video->input_mutex);
if (video_get_input_idx(video, callback, param) == DARRAY_INVALID) {
struct video_input input;
memset(&input, 0, sizeof(input));
input.callback = callback;
input.param = param;
/* TODO: conversion */
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.conversion.format = video->info.format;
input.conversion.width = video->info.width;
input.conversion.height = video->info.height;
}
da_push_back(video->inputs, &input);
if (input.conversion.width == 0)
input.conversion.width = video->info.width;
if (input.conversion.height == 0)
input.conversion.height = video->info.height;
success = video_input_init(&input, video);
if (success)
da_push_back(video->inputs, &input);
}
pthread_mutex_unlock(&video->input_mutex);
return success;
}
void video_output_disconnect(video_t video,
void (*callback)(void *param, const struct video_frame *frame),
void (*callback)(void *param, const struct video_data *frame),
void *param)
{
pthread_mutex_lock(&video->input_mutex);
size_t idx = video_get_input_idx(video, callback, param);
if (idx != DARRAY_INVALID)
if (idx != DARRAY_INVALID) {
video_input_free(video->inputs.array+idx);
da_erase(video->inputs, idx);
}
pthread_mutex_unlock(&video->input_mutex);
}
@ -222,7 +313,7 @@ const struct video_output_info *video_output_getinfo(video_t video)
return &video->info;
}
void video_output_frame(video_t video, struct video_frame *frame)
void video_output_swap_frame(video_t video, struct video_data *frame)
{
pthread_mutex_lock(&video->data_mutex);
video->next_frame = *frame;

View File

@ -18,13 +18,13 @@
#pragma once
#include "media-io-defs.h"
#include "../util/c99defs.h"
#include "video-scaler.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Base video output component. Use this to create an video output track. */
/* Base video output component. Use this to create a video output track. */
struct video_output;
typedef struct video_output *video_t;
@ -47,7 +47,7 @@ enum video_format {
VIDEO_FORMAT_BGRX,
};
struct video_frame {
struct video_data {
const uint8_t *data[MAX_AV_PLANES];
uint32_t linesize[MAX_AV_PLANES];
uint64_t timestamp;
@ -63,12 +63,6 @@ struct video_output_info {
uint32_t height;
};
struct video_convert_info {
enum video_format format;
uint32_t width;
uint32_t height;
};
static inline bool format_is_yuv(enum video_format format)
{
switch (format) {
@ -95,20 +89,20 @@ static inline bool format_is_yuv(enum video_format format)
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_convert_info *conversion,
void (*callback)(void *param, const struct video_frame *frame),
EXPORT bool video_output_connect(video_t video,
struct video_scale_info *conversion,
void (*callback)(void *param, const struct video_data *frame),
void *param);
EXPORT void video_output_disconnect(video_t video,
void (*callback)(void *param, const struct video_frame *frame),
void (*callback)(void *param, const struct video_data *frame),
void *param);
EXPORT const struct video_output_info *video_output_getinfo(video_t video);
EXPORT void video_output_frame(video_t video, struct video_frame *frame);
EXPORT bool video_output_wait(video_t video);
EXPORT void video_output_swap_frame(video_t video, struct video_data *frame);
EXPORT bool video_output_wait(video_t video);
EXPORT uint64_t video_getframetime(video_t video);
EXPORT uint64_t video_gettime(video_t video);
EXPORT void video_output_stop(video_t video);
EXPORT void video_output_stop(video_t video);
#ifdef __cplusplus
}

View File

@ -0,0 +1,146 @@
/******************************************************************************
Copyright (C) 2014 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 "../util/bmem.h"
#include "video-scaler.h"
#include <libswscale/swscale.h>
struct video_scaler {
struct SwsContext *swscale;
int src_height;
};
static inline enum AVPixelFormat get_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_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 inline int get_ffmpeg_scale_type(enum video_scale_type type)
{
switch (type) {
case VIDEO_SCALE_POINT: return SWS_POINT;
case VIDEO_SCALE_FAST_BILINEAR: return SWS_FAST_BILINEAR;
case VIDEO_SCALE_BILINEAR: return SWS_BILINEAR | SWS_AREA;
case VIDEO_SCALE_BICUBIC: return SWS_BICUBIC;
}
return SWS_POINT;
}
static inline const int *get_ffmpeg_coeffs(enum video_colorspace cs)
{
switch (cs) {
case VIDEO_CS_601: return sws_getCoefficients(SWS_CS_ITU601);
case VIDEO_CS_709: return sws_getCoefficients(SWS_CS_ITU709);
}
return sws_getCoefficients(SWS_CS_ITU601);
}
#define FIXED_1_0 (1<<16)
int video_scaler_create(video_scaler_t *scaler_out,
const struct video_scale_info *dst,
const struct video_scale_info *src,
enum video_scale_type type)
{
enum AVPixelFormat format_src = get_ffmpeg_video_format(src->format);
enum AVPixelFormat format_dst = get_ffmpeg_video_format(dst->format);
int scale_type = get_ffmpeg_scale_type(type);
const int *coeff_src = get_ffmpeg_coeffs(src->colorspace);
const int *coeff_dst = get_ffmpeg_coeffs(dst->colorspace);
struct video_scaler *scaler;
int ret;
if (!scaler_out)
return VIDEO_SCALER_FAILED;
if (format_src == AV_PIX_FMT_NONE ||
format_dst == AV_PIX_FMT_NONE)
return VIDEO_SCALER_BAD_CONVERSION;
scaler = bzalloc(sizeof(struct video_scaler));
scaler->src_height = src->height;
scaler->swscale = sws_getCachedContext(NULL,
src->width, src->height, format_src,
dst->width, dst->height, format_dst,
scale_type, NULL, NULL, NULL);
if (!scaler->swscale) {
blog(LOG_WARNING, "video_scaler_create: Could not create "
"swscale");
goto fail;
}
ret = sws_setColorspaceDetails(scaler->swscale,
coeff_src, src->full_range,
coeff_dst, dst->full_range,
0, FIXED_1_0, FIXED_1_0);
if (ret < 0) {
blog(LOG_DEBUG, "video_scaler_create: "
"sws_setColorspaceDetails failed, ignoring");
}
*scaler_out = scaler;
return VIDEO_SCALER_SUCCESS;
fail:
video_scaler_destroy(scaler);
return VIDEO_SCALER_FAILED;
}
void video_scaler_destroy(video_scaler_t scaler)
{
if (scaler) {
sws_freeContext(scaler->swscale);
bfree(scaler);
}
}
bool video_scaler_scale(video_scaler_t scaler,
uint8_t *output[], const uint32_t out_linesize[],
const uint8_t *const input[], const uint32_t in_linesize[])
{
if (!scaler)
return false;
int ret = sws_scale(scaler->swscale,
input, in_linesize,
0, scaler->src_height,
output, out_linesize);
if (ret <= 0) {
blog(LOG_DEBUG, "video_scaler_scale: sws_scale failed: %d",
ret);
return false;
}
return true;
}

View File

@ -0,0 +1,68 @@
/******************************************************************************
Copyright (C) 2014 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 "video-io.h"
#ifdef __cplusplus
extern "C" {
#endif
struct video_scaler;
typedef struct video_scaler *video_scaler_t;
enum video_scale_type {
VIDEO_SCALE_POINT = 0,
VIDEO_SCALE_FAST_BILINEAR = 1,
VIDEO_SCALE_DEFAULT = VIDEO_SCALE_FAST_BILINEAR,
VIDEO_SCALE_BILINEAR = 2,
VIDEO_SCALE_BICUBIC = 3,
};
enum video_colorspace {
VIDEO_CS_601 = 0,
VIDEO_CS_DEFAULT = VIDEO_CS_601,
VIDEO_CS_709 = 1,
};
struct video_scale_info {
enum video_format format;
uint32_t width;
uint32_t height;
bool full_range;
enum video_colorspace colorspace;
};
#define VIDEO_SCALER_SUCCESS 0
#define VIDEO_SCALER_BAD_CONVERSION -1
#define VIDEO_SCALER_FAILED -2
EXPORT int video_scaler_create(video_scaler_t *scaler,
const struct video_scale_info *dst,
const struct video_scale_info *src,
enum video_scale_type type);
EXPORT void video_scaler_destroy(video_scaler_t scaler);
EXPORT bool video_scaler_scale(video_scaler_t scaler,
uint8_t *output[], const uint32_t out_linesize[],
const uint8_t *const input[], const uint32_t in_linesize[]);
#ifdef __cplusplus
}
#endif

View File

@ -18,6 +18,7 @@
#include <inttypes.h>
#include "media-io/format-conversion.h"
#include "media-io/video-frame.h"
#include "util/platform.h"
#include "callback/calldata.h"
#include "graphics/matrix3.h"
@ -166,72 +167,18 @@ fail:
return NULL;
}
#define ALIGN_SIZE(size, align) \
size = (((size)+(align-1)) & (~(align-1)))
/* messy code alarm */
void source_frame_init(struct source_frame *frame,
enum video_format format, uint32_t width, uint32_t height)
void source_frame_init(struct source_frame *frame, enum video_format format,
uint32_t width, uint32_t height)
{
size_t size;
size_t offsets[MAX_AV_PLANES];
int alignment = base_get_alignment();
memset(offsets, 0, sizeof(offsets));
struct video_frame vid_frame;
video_frame_init(&vid_frame, format, width, height);
frame->format = format;
frame->width = width;
frame->height = height;
switch (format) {
case VIDEO_FORMAT_NONE:
return;
case VIDEO_FORMAT_I420:
size = width * height;
ALIGN_SIZE(size, alignment);
offsets[0] = size;
size += (width/2) * (height/2);
ALIGN_SIZE(size, alignment);
offsets[1] = size;
size += (width/2) * (height/2);
ALIGN_SIZE(size, alignment);
frame->data[0] = bmalloc(size);
frame->data[1] = (uint8_t*)frame->data[0] + offsets[0];
frame->data[2] = (uint8_t*)frame->data[0] + offsets[1];
frame->linesize[0] = width;
frame->linesize[1] = width/2;
frame->linesize[2] = width/2;
break;
case VIDEO_FORMAT_NV12:
size = width * height;
ALIGN_SIZE(size, alignment);
offsets[0] = size;
size += (width/2) * (height/2) * 2;
ALIGN_SIZE(size, alignment);
frame->data[0] = bmalloc(size);
frame->data[1] = (uint8_t*)frame->data[0] + offsets[0];
frame->linesize[0] = width;
frame->linesize[1] = width;
break;
case VIDEO_FORMAT_YVYU:
case VIDEO_FORMAT_YUY2:
case VIDEO_FORMAT_UYVY:
size = width * height * 2;
ALIGN_SIZE(size, alignment);
frame->data[0] = bmalloc(size);
frame->linesize[0] = width*2;
break;
case VIDEO_FORMAT_RGBA:
case VIDEO_FORMAT_BGRA:
case VIDEO_FORMAT_BGRX:
size = width * height * 4;
ALIGN_SIZE(size, alignment);
frame->data[0] = bmalloc(size);
frame->linesize[0] = width*4;
break;
for (size_t i = 0; i < MAX_AV_PLANES; i++) {
frame->data[i] = vid_frame.data[i];
frame->linesize[i] = vid_frame.linesize[i];
}
}

View File

@ -238,7 +238,7 @@ static inline void render_video(struct obs_core_video *video, int cur_texture,
/* TODO: replace with more optimal conversion */
static inline bool download_frame(struct obs_core_video *video,
int prev_texture, struct video_frame *frame)
int prev_texture, struct video_data *frame)
{
stagesurf_t surface = video->copy_surfaces[prev_texture];
@ -290,7 +290,7 @@ static inline uint32_t make_aligned_linesize_offset(uint32_t offset,
}
static void fix_gpu_converted_alignment(struct obs_core_video *video,
struct video_frame *frame, int cur_texture)
struct video_data *frame, int cur_texture)
{
struct source_frame *new_frame = &video->convert_frames[cur_texture];
uint32_t src_linesize = frame->linesize[0];
@ -317,7 +317,7 @@ static void fix_gpu_converted_alignment(struct obs_core_video *video,
}
static bool set_gpu_converted_data(struct obs_core_video *video,
struct video_frame *frame, int cur_texture)
struct video_data *frame, int cur_texture)
{
if (frame->linesize[0] == video->output_width*4) {
for (size_t i = 0; i < 3; i++) {
@ -337,7 +337,7 @@ static bool set_gpu_converted_data(struct obs_core_video *video,
}
static bool convert_frame(struct obs_core_video *video,
struct video_frame *frame,
struct video_data *frame,
const struct video_output_info *info, int cur_texture)
{
struct source_frame *new_frame = &video->convert_frames[cur_texture];
@ -368,7 +368,7 @@ static bool convert_frame(struct obs_core_video *video,
}
static inline void output_video_data(struct obs_core_video *video,
struct video_frame *frame, int cur_texture)
struct video_data *frame, int cur_texture)
{
const struct video_output_info *info;
info = video_output_getinfo(video->video);
@ -382,7 +382,7 @@ static inline void output_video_data(struct obs_core_video *video,
return;
}
video_output_frame(video->video, frame);
video_output_swap_frame(video->video, frame);
}
static inline void output_frame(uint64_t timestamp)
@ -390,10 +390,10 @@ static inline void output_frame(uint64_t timestamp)
struct obs_core_video *video = &obs->video;
int cur_texture = video->cur_texture;
int prev_texture = cur_texture == 0 ? NUM_TEXTURES-1 : cur_texture-1;
struct video_frame frame;
struct video_data frame;
bool frame_ready;
memset(&frame, 0, sizeof(struct video_frame));
memset(&frame, 0, sizeof(struct video_data));
frame.timestamp = timestamp;
gs_entercontext(obs_graphics());

View File

@ -399,7 +399,7 @@ static inline int64_t rescale_ts(int64_t val, AVCodecContext *context,
#define YUV420_PLANES 3
static inline void copy_data(AVPicture *pic, const struct video_frame *frame,
static inline void copy_data(AVPicture *pic, const struct video_data *frame,
int height)
{
for (int plane = 0; plane < YUV420_PLANES; plane++) {
@ -420,7 +420,7 @@ static inline void copy_data(AVPicture *pic, const struct video_frame *frame,
}
}
static void receive_video(void *param, const struct video_frame *frame)
static void receive_video(void *param, const struct video_data *frame)
{
struct ffmpeg_output *output = param;
struct ffmpeg_data *data = &output->ff_data;
@ -574,17 +574,17 @@ static bool ffmpeg_output_start(void *data)
if (!ffmpeg_data_init(&output->ff_data, filename_test))
return false;
struct audio_convert_info aci;
aci.samples_per_sec = SPS_TODO;
aci.format = AUDIO_FORMAT_FLOAT_PLANAR;
aci.speakers = SPEAKERS_STEREO;
struct audio_convert_info aci = {
.samples_per_sec = SPS_TODO,
.format = AUDIO_FORMAT_FLOAT_PLANAR,
.speakers = SPEAKERS_STEREO
};
struct video_convert_info vci;
vci.format = VIDEO_FORMAT_I420;
vci.width = 0;
vci.height = 0;
struct video_scale_info vsi = {
.format = VIDEO_FORMAT_I420
};
video_output_connect(video, &vci, receive_video, output);
video_output_connect(video, &vsi, receive_video, output);
audio_output_connect(audio, &aci, receive_audio, output);
output->active = true;

View File

@ -42,7 +42,9 @@
<ClInclude Include="..\..\..\libobs\media-io\audio-io.h" />
<ClInclude Include="..\..\..\libobs\media-io\audio-resampler.h" />
<ClInclude Include="..\..\..\libobs\media-io\format-conversion.h" />
<ClInclude Include="..\..\..\libobs\media-io\video-frame.h" />
<ClInclude Include="..\..\..\libobs\media-io\video-io.h" />
<ClInclude Include="..\..\..\libobs\media-io\video-scaler.h" />
<ClInclude Include="..\..\..\libobs\obs-data.h" />
<ClInclude Include="..\..\..\libobs\obs-defs.h" />
<ClInclude Include="..\..\..\libobs\obs-encoder.h" />
@ -92,7 +94,9 @@
<ClCompile Include="..\..\..\libobs\media-io\audio-io.c" />
<ClCompile Include="..\..\..\libobs\media-io\audio-resampler-ffmpeg.c" />
<ClCompile Include="..\..\..\libobs\media-io\format-conversion.c" />
<ClCompile Include="..\..\..\libobs\media-io\video-frame.c" />
<ClCompile Include="..\..\..\libobs\media-io\video-io.c" />
<ClCompile Include="..\..\..\libobs\media-io\video-scaler-ffmpeg.c" />
<ClCompile Include="..\..\..\libobs\obs-data.c" />
<ClCompile Include="..\..\..\libobs\obs-display.c" />
<ClCompile Include="..\..\..\libobs\obs-encoder.c" />
@ -200,7 +204,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>avutil.lib;swresample.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>avutil.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
@ -221,7 +225,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>avutil.lib;swresample.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>avutil.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
@ -246,7 +250,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>avutil.lib;swresample.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>avutil.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>
@ -271,7 +275,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>avutil.lib;swresample.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>avutil.lib;swresample.lib;swscale.lib;pthreads.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
<PostBuildEvent>

View File

@ -207,6 +207,12 @@
<ClInclude Include="..\..\..\libobs\obs-properties.h">
<Filter>libobs\Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\libobs\media-io\video-scaler.h">
<Filter>media-io\Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\libobs\media-io\video-frame.h">
<Filter>media-io\Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\libobs\obs-output.c">
@ -347,5 +353,11 @@
<ClCompile Include="..\..\..\libobs\obs-view.c">
<Filter>libobs\Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\libobs\media-io\video-scaler-ffmpeg.c">
<Filter>media-io\Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\libobs\media-io\video-frame.c">
<Filter>media-io\Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>