diff options
Diffstat (limited to 'pjmedia/src/pjmedia/converter_libswscale.c')
-rw-r--r-- | pjmedia/src/pjmedia/converter_libswscale.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/pjmedia/src/pjmedia/converter_libswscale.c b/pjmedia/src/pjmedia/converter_libswscale.c new file mode 100644 index 00000000..b9e74a22 --- /dev/null +++ b/pjmedia/src/pjmedia/converter_libswscale.c @@ -0,0 +1,200 @@ +/* $Id$ */ +/* + * Copyright (C) 2010-2011 Teluu Inc. (http://www.teluu.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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjmedia/converter.h> +#include <pj/errno.h> + +#if PJMEDIA_HAS_LIBSWSCALE && PJMEDIA_HAS_LIBAVUTIL + +#include "ffmpeg_util.h" +#include <libswscale/swscale.h> + +static pj_status_t factory_create_converter(pjmedia_converter_factory *cf, + pj_pool_t *pool, + const pjmedia_conversion_param*prm, + pjmedia_converter **p_cv); +static void factory_destroy_factory(pjmedia_converter_factory *cf); +static pj_status_t libswscale_conv_convert(pjmedia_converter *converter, + pjmedia_frame *src_frame, + pjmedia_frame *dst_frame); +static void libswscale_conv_destroy(pjmedia_converter *converter); + + +struct fmt_info +{ + const pjmedia_video_format_info *fmt_info; + pjmedia_video_apply_fmt_param apply_param; +}; + +struct ffmpeg_converter +{ + pjmedia_converter base; + struct SwsContext *sws_ctx; + struct fmt_info src, + dst; +}; + +static pjmedia_converter_factory_op libswscale_factory_op = +{ + &factory_create_converter, + &factory_destroy_factory +}; + +static pjmedia_converter_op liswscale_converter_op = +{ + &libswscale_conv_convert, + &libswscale_conv_destroy +}; + +static pj_status_t factory_create_converter(pjmedia_converter_factory *cf, + pj_pool_t *pool, + const pjmedia_conversion_param *prm, + pjmedia_converter **p_cv) +{ + enum PixelFormat srcFormat, dstFormat; + const pjmedia_video_format_detail *src_detail, *dst_detail; + const pjmedia_video_format_info *src_fmt_info, *dst_fmt_info; + struct SwsContext *sws_ctx; + struct ffmpeg_converter *fcv; + pj_status_t status; + + PJ_UNUSED_ARG(cf); + + /* Only supports video */ + if (prm->src.type != PJMEDIA_TYPE_VIDEO || + prm->dst.type != prm->src.type || + prm->src.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO || + prm->dst.detail_type != prm->src.detail_type) + { + return PJ_ENOTSUP; + } + + /* lookup source format info */ + src_fmt_info = pjmedia_get_video_format_info( + pjmedia_video_format_mgr_instance(), + prm->src.id); + if (!src_fmt_info) + return PJ_ENOTSUP; + + /* lookup destination format info */ + dst_fmt_info = pjmedia_get_video_format_info( + pjmedia_video_format_mgr_instance(), + prm->dst.id); + if (!dst_fmt_info) + return PJ_ENOTSUP; + + src_detail = pjmedia_format_get_video_format_detail(&prm->src, PJ_TRUE); + dst_detail = pjmedia_format_get_video_format_detail(&prm->dst, PJ_TRUE); + + status = pjmedia_format_id_to_PixelFormat(prm->src.id, &srcFormat); + if (status != PJ_SUCCESS) + return PJ_ENOTSUP; + + status = pjmedia_format_id_to_PixelFormat(prm->dst.id, &dstFormat); + if (status != PJ_SUCCESS) + return PJ_ENOTSUP; + + sws_ctx = sws_getContext(src_detail->size.w, src_detail->size.h, srcFormat, + dst_detail->size.w, dst_detail->size.h, dstFormat, + SWS_BICUBIC, + NULL, NULL, NULL); + if (sws_ctx == NULL) + return PJ_ENOTSUP; + + fcv = PJ_POOL_ZALLOC_T(pool, struct ffmpeg_converter); + fcv->base.op = &liswscale_converter_op; + fcv->sws_ctx = sws_ctx; + fcv->src.apply_param.size = src_detail->size; + fcv->src.fmt_info = src_fmt_info; + fcv->dst.apply_param.size = dst_detail->size; + fcv->dst.fmt_info = dst_fmt_info; + + *p_cv = &fcv->base; + + return PJ_SUCCESS; +} + +static void factory_destroy_factory(pjmedia_converter_factory *cf) +{ + PJ_UNUSED_ARG(cf); +} + +static pj_status_t libswscale_conv_convert(pjmedia_converter *converter, + pjmedia_frame *src_frame, + pjmedia_frame *dst_frame) +{ + struct ffmpeg_converter *fcv = (struct ffmpeg_converter*)converter; + struct fmt_info *src = &fcv->src, + *dst = &fcv->dst; + int h; + + src->apply_param.buffer = src_frame->buf; + (*src->fmt_info->apply_fmt)(src->fmt_info, &src->apply_param); + + dst->apply_param.buffer = dst_frame->buf; + (*dst->fmt_info->apply_fmt)(dst->fmt_info, &dst->apply_param); + + h = sws_scale(fcv->sws_ctx, + src->apply_param.planes, src->apply_param.strides, + 0, src->apply_param.size.h, + dst->apply_param.planes, dst->apply_param.strides); + + return h==(int)dst->apply_param.size.h ? PJ_SUCCESS : PJ_EUNKNOWN; +} + +static void libswscale_conv_destroy(pjmedia_converter *converter) +{ + struct ffmpeg_converter *fcv = (struct ffmpeg_converter*)converter; + if (fcv->sws_ctx) { + struct SwsContext *tmp = fcv->sws_ctx; + fcv->sws_ctx = NULL; + sws_freeContext(tmp); + } +} + +static pjmedia_converter_factory libswscale_factory = +{ + NULL, NULL, /* list */ + "libswscale", /* name */ + PJMEDIA_CONVERTER_PRIORITY_NORMAL+1, /* priority */ + NULL /* op will be init-ed later */ +}; + +PJ_DEF(pj_status_t) +pjmedia_libswscale_converter_init(pjmedia_converter_mgr *mgr) +{ + libswscale_factory.op = &libswscale_factory_op; + return pjmedia_converter_mgr_register_factory(mgr, &libswscale_factory); +} + + +PJ_DEF(pj_status_t) +pjmedia_libswscale_converter_shutdown(pjmedia_converter_mgr *mgr, + pj_pool_t *pool) +{ + PJ_UNUSED_ARG(pool); + return pjmedia_converter_mgr_unregister_factory(mgr, &libswscale_factory, + PJ_TRUE); +} + +#ifdef _MSC_VER +# pragma comment( lib, "avutil.lib") +# pragma comment( lib, "swscale.lib") +#endif + +#endif /* #if PJMEDIA_HAS_LIBSWSCALE && PJMEDIA_HAS_LIBAVUTIL */ |