vf_framepack.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. /*
  2. * Copyright (c) 2013 Vittorio Giovara
  3. *
  4. * This file is part of Libav.
  5. *
  6. * Libav is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * Libav is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with Libav; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. /**
  21. * @file
  22. * Generate a frame packed video, by combining two views in a single surface.
  23. */
  24. #include <string.h>
  25. #include "libavutil/common.h"
  26. #include "libavutil/imgutils.h"
  27. #include "libavutil/opt.h"
  28. #include "libavutil/pixdesc.h"
  29. #include "libavutil/rational.h"
  30. #include "libavutil/stereo3d.h"
  31. #include "avfilter.h"
  32. #include "formats.h"
  33. #include "internal.h"
  34. #include "video.h"
  35. #define LEFT 0
  36. #define RIGHT 1
  37. typedef struct FramepackContext {
  38. const AVClass *class;
  39. const AVPixFmtDescriptor *pix_desc; ///< agreed pixel format
  40. enum AVStereo3DType format; ///< frame pack type output
  41. AVFrame *input_views[2]; ///< input frames
  42. int64_t double_pts; ///< new pts for frameseq mode
  43. } FramepackContext;
  44. static const enum AVPixelFormat formats_supported[] = {
  45. AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P,
  46. AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVJ420P,
  47. AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P,
  48. AV_PIX_FMT_NONE
  49. };
  50. static int query_formats(AVFilterContext *ctx)
  51. {
  52. // this will ensure that formats are the same on all pads
  53. ff_set_common_formats(ctx, ff_make_format_list(formats_supported));
  54. return 0;
  55. }
  56. static av_cold void framepack_uninit(AVFilterContext *ctx)
  57. {
  58. FramepackContext *s = ctx->priv;
  59. // clean any leftover frame
  60. av_frame_free(&s->input_views[LEFT]);
  61. av_frame_free(&s->input_views[RIGHT]);
  62. }
  63. static int config_output(AVFilterLink *outlink)
  64. {
  65. AVFilterContext *ctx = outlink->src;
  66. FramepackContext *s = outlink->src->priv;
  67. int width = ctx->inputs[LEFT]->w;
  68. int height = ctx->inputs[LEFT]->h;
  69. AVRational time_base = ctx->inputs[LEFT]->time_base;
  70. AVRational frame_rate = ctx->inputs[LEFT]->frame_rate;
  71. // check size and fps match on the other input
  72. if (width != ctx->inputs[RIGHT]->w ||
  73. height != ctx->inputs[RIGHT]->h) {
  74. av_log(ctx, AV_LOG_ERROR,
  75. "Left and right sizes differ (%dx%d vs %dx%d).\n",
  76. width, height,
  77. ctx->inputs[RIGHT]->w, ctx->inputs[RIGHT]->h);
  78. return AVERROR_INVALIDDATA;
  79. } else if (av_cmp_q(time_base, ctx->inputs[RIGHT]->time_base) != 0) {
  80. av_log(ctx, AV_LOG_ERROR,
  81. "Left and right time bases differ (%d/%d vs %d/%d).\n",
  82. time_base.num, time_base.den,
  83. ctx->inputs[RIGHT]->time_base.num,
  84. ctx->inputs[RIGHT]->time_base.den);
  85. return AVERROR_INVALIDDATA;
  86. } else if (av_cmp_q(frame_rate, ctx->inputs[RIGHT]->frame_rate) != 0) {
  87. av_log(ctx, AV_LOG_ERROR,
  88. "Left and right framerates differ (%d/%d vs %d/%d).\n",
  89. frame_rate.num, frame_rate.den,
  90. ctx->inputs[RIGHT]->frame_rate.num,
  91. ctx->inputs[RIGHT]->frame_rate.den);
  92. return AVERROR_INVALIDDATA;
  93. }
  94. s->pix_desc = av_pix_fmt_desc_get(outlink->format);
  95. if (!s->pix_desc)
  96. return AVERROR_BUG;
  97. // modify output properties as needed
  98. switch (s->format) {
  99. case AV_STEREO3D_FRAMESEQUENCE:
  100. time_base.den *= 2;
  101. frame_rate.num *= 2;
  102. s->double_pts = AV_NOPTS_VALUE;
  103. break;
  104. case AV_STEREO3D_COLUMNS:
  105. case AV_STEREO3D_SIDEBYSIDE:
  106. width *= 2;
  107. break;
  108. case AV_STEREO3D_LINES:
  109. case AV_STEREO3D_TOPBOTTOM:
  110. height *= 2;
  111. break;
  112. default:
  113. av_log(ctx, AV_LOG_ERROR, "Unknown packing mode.");
  114. return AVERROR_INVALIDDATA;
  115. }
  116. outlink->w = width;
  117. outlink->h = height;
  118. outlink->time_base = time_base;
  119. outlink->frame_rate = frame_rate;
  120. return 0;
  121. }
  122. static void horizontal_frame_pack(AVFilterLink *outlink,
  123. AVFrame *out,
  124. int interleaved)
  125. {
  126. AVFilterContext *ctx = outlink->src;
  127. FramepackContext *s = ctx->priv;
  128. int i, plane;
  129. if (interleaved) {
  130. const uint8_t *leftp = s->input_views[LEFT]->data[0];
  131. const uint8_t *rightp = s->input_views[RIGHT]->data[0];
  132. uint8_t *dstp = out->data[0];
  133. int length = out->width / 2;
  134. int lines = out->height;
  135. for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
  136. if (plane == 1 || plane == 2) {
  137. length = AV_CEIL_RSHIFT(out->width / 2, s->pix_desc->log2_chroma_w);
  138. lines = AV_CEIL_RSHIFT(out->height, s->pix_desc->log2_chroma_h);
  139. }
  140. for (i = 0; i < lines; i++) {
  141. int j;
  142. leftp = s->input_views[LEFT]->data[plane] +
  143. s->input_views[LEFT]->linesize[plane] * i;
  144. rightp = s->input_views[RIGHT]->data[plane] +
  145. s->input_views[RIGHT]->linesize[plane] * i;
  146. dstp = out->data[plane] + out->linesize[plane] * i;
  147. for (j = 0; j < length; j++) {
  148. // interpolate chroma as necessary
  149. if ((s->pix_desc->log2_chroma_w ||
  150. s->pix_desc->log2_chroma_h) &&
  151. (plane == 1 || plane == 2)) {
  152. *dstp++ = (*leftp + *rightp) / 2;
  153. *dstp++ = (*leftp + *rightp) / 2;
  154. } else {
  155. *dstp++ = *leftp;
  156. *dstp++ = *rightp;
  157. }
  158. leftp += 1;
  159. rightp += 1;
  160. }
  161. }
  162. }
  163. } else {
  164. for (i = 0; i < 2; i++) {
  165. const uint8_t *src[4];
  166. uint8_t *dst[4];
  167. int sub_w = s->input_views[i]->width >> s->pix_desc->log2_chroma_w;
  168. src[0] = s->input_views[i]->data[0];
  169. src[1] = s->input_views[i]->data[1];
  170. src[2] = s->input_views[i]->data[2];
  171. dst[0] = out->data[0] + i * s->input_views[i]->width;
  172. dst[1] = out->data[1] + i * sub_w;
  173. dst[2] = out->data[2] + i * sub_w;
  174. av_image_copy(dst, out->linesize, src, s->input_views[i]->linesize,
  175. s->input_views[i]->format,
  176. s->input_views[i]->width,
  177. s->input_views[i]->height);
  178. }
  179. }
  180. }
  181. static void vertical_frame_pack(AVFilterLink *outlink,
  182. AVFrame *out,
  183. int interleaved)
  184. {
  185. AVFilterContext *ctx = outlink->src;
  186. FramepackContext *s = ctx->priv;
  187. int i;
  188. for (i = 0; i < 2; i++) {
  189. const uint8_t *src[4];
  190. uint8_t *dst[4];
  191. int linesizes[4];
  192. int sub_h = s->input_views[i]->height >> s->pix_desc->log2_chroma_h;
  193. src[0] = s->input_views[i]->data[0];
  194. src[1] = s->input_views[i]->data[1];
  195. src[2] = s->input_views[i]->data[2];
  196. dst[0] = out->data[0] + i * out->linesize[0] *
  197. (interleaved + s->input_views[i]->height * (1 - interleaved));
  198. dst[1] = out->data[1] + i * out->linesize[1] *
  199. (interleaved + sub_h * (1 - interleaved));
  200. dst[2] = out->data[2] + i * out->linesize[2] *
  201. (interleaved + sub_h * (1 - interleaved));
  202. linesizes[0] = out->linesize[0] +
  203. interleaved * out->linesize[0];
  204. linesizes[1] = out->linesize[1] +
  205. interleaved * out->linesize[1];
  206. linesizes[2] = out->linesize[2] +
  207. interleaved * out->linesize[2];
  208. av_image_copy(dst, linesizes, src, s->input_views[i]->linesize,
  209. s->input_views[i]->format,
  210. s->input_views[i]->width,
  211. s->input_views[i]->height);
  212. }
  213. }
  214. static av_always_inline void spatial_frame_pack(AVFilterLink *outlink,
  215. AVFrame *dst)
  216. {
  217. AVFilterContext *ctx = outlink->src;
  218. FramepackContext *s = ctx->priv;
  219. switch (s->format) {
  220. case AV_STEREO3D_SIDEBYSIDE:
  221. horizontal_frame_pack(outlink, dst, 0);
  222. break;
  223. case AV_STEREO3D_COLUMNS:
  224. horizontal_frame_pack(outlink, dst, 1);
  225. break;
  226. case AV_STEREO3D_TOPBOTTOM:
  227. vertical_frame_pack(outlink, dst, 0);
  228. break;
  229. case AV_STEREO3D_LINES:
  230. vertical_frame_pack(outlink, dst, 1);
  231. break;
  232. }
  233. }
  234. static int filter_frame_left(AVFilterLink *inlink, AVFrame *frame)
  235. {
  236. FramepackContext *s = inlink->dst->priv;
  237. s->input_views[LEFT] = frame;
  238. return 0;
  239. }
  240. static int filter_frame_right(AVFilterLink *inlink, AVFrame *frame)
  241. {
  242. FramepackContext *s = inlink->dst->priv;
  243. s->input_views[RIGHT] = frame;
  244. return 0;
  245. }
  246. static int request_frame(AVFilterLink *outlink)
  247. {
  248. AVFilterContext *ctx = outlink->src;
  249. FramepackContext *s = ctx->priv;
  250. AVStereo3D *stereo;
  251. int ret, i;
  252. /* get a frame on the either input, stop as soon as a video ends */
  253. for (i = 0; i < 2; i++) {
  254. if (!s->input_views[i]) {
  255. ret = ff_request_frame(ctx->inputs[i]);
  256. if (ret < 0)
  257. return ret;
  258. }
  259. }
  260. if (s->format == AV_STEREO3D_FRAMESEQUENCE) {
  261. if (s->double_pts == AV_NOPTS_VALUE)
  262. s->double_pts = s->input_views[LEFT]->pts;
  263. for (i = 0; i < 2; i++) {
  264. // set correct timestamps
  265. s->input_views[i]->pts = s->double_pts++;
  266. // set stereo3d side data
  267. stereo = av_stereo3d_create_side_data(s->input_views[i]);
  268. if (!stereo)
  269. return AVERROR(ENOMEM);
  270. stereo->type = s->format;
  271. // filter the frame and immediately relinquish its pointer
  272. ret = ff_filter_frame(outlink, s->input_views[i]);
  273. s->input_views[i] = NULL;
  274. if (ret < 0)
  275. return ret;
  276. }
  277. return ret;
  278. } else {
  279. AVFrame *dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  280. if (!dst)
  281. return AVERROR(ENOMEM);
  282. spatial_frame_pack(outlink, dst);
  283. // get any property from the original frame
  284. ret = av_frame_copy_props(dst, s->input_views[LEFT]);
  285. if (ret < 0) {
  286. av_frame_free(&dst);
  287. return ret;
  288. }
  289. for (i = 0; i < 2; i++)
  290. av_frame_free(&s->input_views[i]);
  291. // set stereo3d side data
  292. stereo = av_stereo3d_create_side_data(dst);
  293. if (!stereo) {
  294. av_frame_free(&dst);
  295. return AVERROR(ENOMEM);
  296. }
  297. stereo->type = s->format;
  298. return ff_filter_frame(outlink, dst);
  299. }
  300. }
  301. #define OFFSET(x) offsetof(FramepackContext, x)
  302. #define V AV_OPT_FLAG_VIDEO_PARAM
  303. static const AVOption options[] = {
  304. { "format", "Frame pack output format", OFFSET(format), AV_OPT_TYPE_INT,
  305. { .i64 = AV_STEREO3D_SIDEBYSIDE }, 0, INT_MAX, .flags = V, .unit = "format" },
  306. { "sbs", "Views are packed next to each other", 0, AV_OPT_TYPE_CONST,
  307. { .i64 = AV_STEREO3D_SIDEBYSIDE }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  308. { "tab", "Views are packed on top of each other", 0, AV_OPT_TYPE_CONST,
  309. { .i64 = AV_STEREO3D_TOPBOTTOM }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  310. { "frameseq", "Views are one after the other", 0, AV_OPT_TYPE_CONST,
  311. { .i64 = AV_STEREO3D_FRAMESEQUENCE }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  312. { "lines", "Views are interleaved by lines", 0, AV_OPT_TYPE_CONST,
  313. { .i64 = AV_STEREO3D_LINES }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  314. { "columns", "Views are interleaved by columns", 0, AV_OPT_TYPE_CONST,
  315. { .i64 = AV_STEREO3D_COLUMNS }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  316. { NULL },
  317. };
  318. static const AVClass framepack_class = {
  319. .class_name = "framepack",
  320. .item_name = av_default_item_name,
  321. .option = options,
  322. .version = LIBAVUTIL_VERSION_INT,
  323. };
  324. static const AVFilterPad framepack_inputs[] = {
  325. {
  326. .name = "left",
  327. .type = AVMEDIA_TYPE_VIDEO,
  328. .filter_frame = filter_frame_left,
  329. .needs_fifo = 1,
  330. },
  331. {
  332. .name = "right",
  333. .type = AVMEDIA_TYPE_VIDEO,
  334. .filter_frame = filter_frame_right,
  335. .needs_fifo = 1,
  336. },
  337. { NULL }
  338. };
  339. static const AVFilterPad framepack_outputs[] = {
  340. {
  341. .name = "packed",
  342. .type = AVMEDIA_TYPE_VIDEO,
  343. .config_props = config_output,
  344. .request_frame = request_frame,
  345. },
  346. { NULL }
  347. };
  348. AVFilter ff_vf_framepack = {
  349. .name = "framepack",
  350. .description = NULL_IF_CONFIG_SMALL("Generate a frame packed stereoscopic video."),
  351. .priv_size = sizeof(FramepackContext),
  352. .priv_class = &framepack_class,
  353. .query_formats = query_formats,
  354. .inputs = framepack_inputs,
  355. .outputs = framepack_outputs,
  356. .uninit = framepack_uninit,
  357. };