Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjmedia / src / pjmedia / converter_libswscale.c
1 /* $Id$ */
2 /*
3  * Copyright (C) 2010-2011 Teluu Inc. (http://www.teluu.com)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include <pjmedia/converter.h>
20 #include <pj/errno.h>
21
22 #if PJMEDIA_HAS_LIBSWSCALE && PJMEDIA_HAS_LIBAVUTIL
23
24 #include "ffmpeg_util.h"
25 #include <libswscale/swscale.h>
26
27 static pj_status_t factory_create_converter(pjmedia_converter_factory *cf,
28                                             pj_pool_t *pool,
29                                             const pjmedia_conversion_param*prm,
30                                             pjmedia_converter **p_cv);
31 static void factory_destroy_factory(pjmedia_converter_factory *cf);
32 static pj_status_t libswscale_conv_convert(pjmedia_converter *converter,
33                                            pjmedia_frame *src_frame,
34                                            pjmedia_frame *dst_frame);
35 static void libswscale_conv_destroy(pjmedia_converter *converter);
36
37
38 struct fmt_info
39 {
40     const pjmedia_video_format_info     *fmt_info;
41     pjmedia_video_apply_fmt_param        apply_param;
42 };
43
44 struct ffmpeg_converter
45 {
46     pjmedia_converter                    base;
47     struct SwsContext                   *sws_ctx;
48     struct fmt_info                      src,
49                                          dst;
50 };
51
52 static pjmedia_converter_factory_op libswscale_factory_op =
53 {
54     &factory_create_converter,
55     &factory_destroy_factory
56 };
57
58 static pjmedia_converter_op liswscale_converter_op =
59 {
60     &libswscale_conv_convert,
61     &libswscale_conv_destroy
62 };
63
64 static pj_status_t factory_create_converter(pjmedia_converter_factory *cf,
65                                             pj_pool_t *pool,
66                                             const pjmedia_conversion_param *prm,
67                                             pjmedia_converter **p_cv)
68 {
69     enum PixelFormat srcFormat, dstFormat;
70     const pjmedia_video_format_detail *src_detail, *dst_detail;
71     const pjmedia_video_format_info *src_fmt_info, *dst_fmt_info;
72     struct SwsContext *sws_ctx;
73     struct ffmpeg_converter *fcv;
74     pj_status_t status;
75
76     PJ_UNUSED_ARG(cf);
77
78     /* Only supports video */
79     if (prm->src.type != PJMEDIA_TYPE_VIDEO ||
80         prm->dst.type != prm->src.type ||
81         prm->src.detail_type != PJMEDIA_FORMAT_DETAIL_VIDEO ||
82         prm->dst.detail_type != prm->src.detail_type)
83     {
84         return PJ_ENOTSUP;
85     }
86
87     /* lookup source format info */
88     src_fmt_info = pjmedia_get_video_format_info(
89                       pjmedia_video_format_mgr_instance(),
90                       prm->src.id);
91     if (!src_fmt_info)
92         return PJ_ENOTSUP;
93
94     /* lookup destination format info */
95     dst_fmt_info = pjmedia_get_video_format_info(
96                       pjmedia_video_format_mgr_instance(),
97                       prm->dst.id);
98     if (!dst_fmt_info)
99         return PJ_ENOTSUP;
100
101     src_detail = pjmedia_format_get_video_format_detail(&prm->src, PJ_TRUE);
102     dst_detail = pjmedia_format_get_video_format_detail(&prm->dst, PJ_TRUE);
103
104     status = pjmedia_format_id_to_PixelFormat(prm->src.id, &srcFormat);
105     if (status != PJ_SUCCESS)
106         return PJ_ENOTSUP;
107
108     status = pjmedia_format_id_to_PixelFormat(prm->dst.id, &dstFormat);
109     if (status != PJ_SUCCESS)
110         return PJ_ENOTSUP;
111
112     sws_ctx = sws_getContext(src_detail->size.w, src_detail->size.h, srcFormat,
113                              dst_detail->size.w, dst_detail->size.h, dstFormat,
114                              SWS_BICUBIC,
115                              NULL, NULL, NULL);
116     if (sws_ctx == NULL)
117         return PJ_ENOTSUP;
118
119     fcv = PJ_POOL_ZALLOC_T(pool, struct ffmpeg_converter);
120     fcv->base.op = &liswscale_converter_op;
121     fcv->sws_ctx = sws_ctx;
122     fcv->src.apply_param.size = src_detail->size;
123     fcv->src.fmt_info = src_fmt_info;
124     fcv->dst.apply_param.size = dst_detail->size;
125     fcv->dst.fmt_info = dst_fmt_info;
126
127     *p_cv = &fcv->base;
128
129     return PJ_SUCCESS;
130 }
131
132 static void factory_destroy_factory(pjmedia_converter_factory *cf)
133 {
134     PJ_UNUSED_ARG(cf);
135 }
136
137 static pj_status_t libswscale_conv_convert(pjmedia_converter *converter,
138                                            pjmedia_frame *src_frame,
139                                            pjmedia_frame *dst_frame)
140 {
141     struct ffmpeg_converter *fcv = (struct ffmpeg_converter*)converter;
142     struct fmt_info *src = &fcv->src,
143                     *dst = &fcv->dst;
144     int h;
145
146     src->apply_param.buffer = src_frame->buf;
147     (*src->fmt_info->apply_fmt)(src->fmt_info, &src->apply_param);
148
149     dst->apply_param.buffer = dst_frame->buf;
150     (*dst->fmt_info->apply_fmt)(dst->fmt_info, &dst->apply_param);
151
152     h = sws_scale(fcv->sws_ctx,
153                   (const uint8_t* const *)src->apply_param.planes,
154                   src->apply_param.strides,
155                   0, src->apply_param.size.h,
156                   dst->apply_param.planes, dst->apply_param.strides);
157
158     //sws_scale() return value can't be trusted? There are cases when
159     //sws_scale() returns zero but conversion seems to work okay.
160     //return h==(int)dst->apply_param.size.h ? PJ_SUCCESS : PJ_EUNKNOWN;
161     PJ_UNUSED_ARG(h);
162
163     return PJ_SUCCESS;
164 }
165
166 static void libswscale_conv_destroy(pjmedia_converter *converter)
167 {
168     struct ffmpeg_converter *fcv = (struct ffmpeg_converter*)converter;
169     if (fcv->sws_ctx) {
170         struct SwsContext *tmp = fcv->sws_ctx;
171         fcv->sws_ctx = NULL;
172         sws_freeContext(tmp);
173     }
174 }
175
176 static pjmedia_converter_factory libswscale_factory =
177 {
178     NULL, NULL,                                 /* list */
179     "libswscale",                               /* name */
180     PJMEDIA_CONVERTER_PRIORITY_NORMAL+1,        /* priority */
181     NULL                                        /* op will be init-ed later  */
182 };
183
184 PJ_DEF(pj_status_t)
185 pjmedia_libswscale_converter_init(pjmedia_converter_mgr *mgr)
186 {
187     libswscale_factory.op = &libswscale_factory_op;
188     pjmedia_ffmpeg_add_ref();
189     return pjmedia_converter_mgr_register_factory(mgr, &libswscale_factory);
190 }
191
192
193 PJ_DEF(pj_status_t)
194 pjmedia_libswscale_converter_shutdown(pjmedia_converter_mgr *mgr,
195                                       pj_pool_t *pool)
196 {
197     PJ_UNUSED_ARG(pool);
198     pjmedia_ffmpeg_dec_ref();
199     return pjmedia_converter_mgr_unregister_factory(mgr, &libswscale_factory,
200                                                     PJ_TRUE);
201 }
202
203 #ifdef _MSC_VER
204 #   pragma comment( lib, "avutil.lib")
205 #   pragma comment( lib, "swscale.lib")
206 #endif
207
208 #endif /* #if PJMEDIA_HAS_LIBSWSCALE && PJMEDIA_HAS_LIBAVUTIL */