vf_framepack.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /*
  2. * Copyright (c) 2013 Vittorio Giovara
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg 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. * FFmpeg 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 FFmpeg; 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. AVFilterFormats *fmts_list = ff_make_format_list(formats_supported);
  54. if (!fmts_list)
  55. return AVERROR(ENOMEM);
  56. return ff_set_common_formats(ctx, fmts_list);
  57. }
  58. static av_cold void framepack_uninit(AVFilterContext *ctx)
  59. {
  60. FramepackContext *s = ctx->priv;
  61. // clean any leftover frame
  62. av_frame_free(&s->input_views[LEFT]);
  63. av_frame_free(&s->input_views[RIGHT]);
  64. }
  65. static int config_output(AVFilterLink *outlink)
  66. {
  67. AVFilterContext *ctx = outlink->src;
  68. FramepackContext *s = outlink->src->priv;
  69. int width = ctx->inputs[LEFT]->w;
  70. int height = ctx->inputs[LEFT]->h;
  71. AVRational time_base = ctx->inputs[LEFT]->time_base;
  72. AVRational frame_rate = ctx->inputs[LEFT]->frame_rate;
  73. // check size and fps match on the other input
  74. if (width != ctx->inputs[RIGHT]->w ||
  75. height != ctx->inputs[RIGHT]->h) {
  76. av_log(ctx, AV_LOG_ERROR,
  77. "Left and right sizes differ (%dx%d vs %dx%d).\n",
  78. width, height,
  79. ctx->inputs[RIGHT]->w, ctx->inputs[RIGHT]->h);
  80. return AVERROR_INVALIDDATA;
  81. } else if (av_cmp_q(time_base, ctx->inputs[RIGHT]->time_base) != 0) {
  82. av_log(ctx, AV_LOG_ERROR,
  83. "Left and right time bases differ (%d/%d vs %d/%d).\n",
  84. time_base.num, time_base.den,
  85. ctx->inputs[RIGHT]->time_base.num,
  86. ctx->inputs[RIGHT]->time_base.den);
  87. return AVERROR_INVALIDDATA;
  88. } else if (av_cmp_q(frame_rate, ctx->inputs[RIGHT]->frame_rate) != 0) {
  89. av_log(ctx, AV_LOG_ERROR,
  90. "Left and right framerates differ (%d/%d vs %d/%d).\n",
  91. frame_rate.num, frame_rate.den,
  92. ctx->inputs[RIGHT]->frame_rate.num,
  93. ctx->inputs[RIGHT]->frame_rate.den);
  94. return AVERROR_INVALIDDATA;
  95. }
  96. s->pix_desc = av_pix_fmt_desc_get(outlink->format);
  97. if (!s->pix_desc)
  98. return AVERROR_BUG;
  99. // modify output properties as needed
  100. switch (s->format) {
  101. case AV_STEREO3D_FRAMESEQUENCE:
  102. time_base.den *= 2;
  103. frame_rate.num *= 2;
  104. s->double_pts = AV_NOPTS_VALUE;
  105. break;
  106. case AV_STEREO3D_COLUMNS:
  107. case AV_STEREO3D_SIDEBYSIDE:
  108. width *= 2;
  109. break;
  110. case AV_STEREO3D_LINES:
  111. case AV_STEREO3D_TOPBOTTOM:
  112. height *= 2;
  113. break;
  114. default:
  115. av_log(ctx, AV_LOG_ERROR, "Unknown packing mode.");
  116. return AVERROR_INVALIDDATA;
  117. }
  118. outlink->w = width;
  119. outlink->h = height;
  120. outlink->time_base = time_base;
  121. outlink->frame_rate = frame_rate;
  122. return 0;
  123. }
  124. static void horizontal_frame_pack(AVFilterLink *outlink,
  125. AVFrame *out,
  126. int interleaved)
  127. {
  128. AVFilterContext *ctx = outlink->src;
  129. FramepackContext *s = ctx->priv;
  130. int i, plane;
  131. if (interleaved) {
  132. const uint8_t *leftp = s->input_views[LEFT]->data[0];
  133. const uint8_t *rightp = s->input_views[RIGHT]->data[0];
  134. uint8_t *dstp = out->data[0];
  135. int length = out->width / 2;
  136. int lines = out->height;
  137. for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
  138. if (plane == 1 || plane == 2) {
  139. length = AV_CEIL_RSHIFT(out->width / 2, s->pix_desc->log2_chroma_w);
  140. lines = AV_CEIL_RSHIFT(out->height, s->pix_desc->log2_chroma_h);
  141. }
  142. for (i = 0; i < lines; i++) {
  143. int j;
  144. leftp = s->input_views[LEFT]->data[plane] +
  145. s->input_views[LEFT]->linesize[plane] * i;
  146. rightp = s->input_views[RIGHT]->data[plane] +
  147. s->input_views[RIGHT]->linesize[plane] * i;
  148. dstp = out->data[plane] + out->linesize[plane] * i;
  149. for (j = 0; j < length; j++) {
  150. // interpolate chroma as necessary
  151. if ((s->pix_desc->log2_chroma_w ||
  152. s->pix_desc->log2_chroma_h) &&
  153. (plane == 1 || plane == 2)) {
  154. *dstp++ = (*leftp + *rightp) / 2;
  155. *dstp++ = (*leftp + *rightp) / 2;
  156. } else {
  157. *dstp++ = *leftp;
  158. *dstp++ = *rightp;
  159. }
  160. leftp += 1;
  161. rightp += 1;
  162. }
  163. }
  164. }
  165. } else {
  166. for (i = 0; i < 2; i++) {
  167. const uint8_t *src[4];
  168. uint8_t *dst[4];
  169. int sub_w = s->input_views[i]->width >> s->pix_desc->log2_chroma_w;
  170. src[0] = s->input_views[i]->data[0];
  171. src[1] = s->input_views[i]->data[1];
  172. src[2] = s->input_views[i]->data[2];
  173. dst[0] = out->data[0] + i * s->input_views[i]->width;
  174. dst[1] = out->data[1] + i * sub_w;
  175. dst[2] = out->data[2] + i * sub_w;
  176. av_image_copy(dst, out->linesize, src, s->input_views[i]->linesize,
  177. s->input_views[i]->format,
  178. s->input_views[i]->width,
  179. s->input_views[i]->height);
  180. }
  181. }
  182. }
  183. static void vertical_frame_pack(AVFilterLink *outlink,
  184. AVFrame *out,
  185. int interleaved)
  186. {
  187. AVFilterContext *ctx = outlink->src;
  188. FramepackContext *s = ctx->priv;
  189. int i;
  190. for (i = 0; i < 2; i++) {
  191. const uint8_t *src[4];
  192. uint8_t *dst[4];
  193. int linesizes[4];
  194. int sub_h = s->input_views[i]->height >> s->pix_desc->log2_chroma_h;
  195. src[0] = s->input_views[i]->data[0];
  196. src[1] = s->input_views[i]->data[1];
  197. src[2] = s->input_views[i]->data[2];
  198. dst[0] = out->data[0] + i * out->linesize[0] *
  199. (interleaved + s->input_views[i]->height * (1 - interleaved));
  200. dst[1] = out->data[1] + i * out->linesize[1] *
  201. (interleaved + sub_h * (1 - interleaved));
  202. dst[2] = out->data[2] + i * out->linesize[2] *
  203. (interleaved + sub_h * (1 - interleaved));
  204. linesizes[0] = out->linesize[0] +
  205. interleaved * out->linesize[0];
  206. linesizes[1] = out->linesize[1] +
  207. interleaved * out->linesize[1];
  208. linesizes[2] = out->linesize[2] +
  209. interleaved * out->linesize[2];
  210. av_image_copy(dst, linesizes, src, s->input_views[i]->linesize,
  211. s->input_views[i]->format,
  212. s->input_views[i]->width,
  213. s->input_views[i]->height);
  214. }
  215. }
  216. static av_always_inline void spatial_frame_pack(AVFilterLink *outlink,
  217. AVFrame *dst)
  218. {
  219. AVFilterContext *ctx = outlink->src;
  220. FramepackContext *s = ctx->priv;
  221. switch (s->format) {
  222. case AV_STEREO3D_SIDEBYSIDE:
  223. horizontal_frame_pack(outlink, dst, 0);
  224. break;
  225. case AV_STEREO3D_COLUMNS:
  226. horizontal_frame_pack(outlink, dst, 1);
  227. break;
  228. case AV_STEREO3D_TOPBOTTOM:
  229. vertical_frame_pack(outlink, dst, 0);
  230. break;
  231. case AV_STEREO3D_LINES:
  232. vertical_frame_pack(outlink, dst, 1);
  233. break;
  234. }
  235. }
  236. static int try_push_frame(AVFilterContext *ctx);
  237. static int filter_frame_left(AVFilterLink *inlink, AVFrame *frame)
  238. {
  239. FramepackContext *s = inlink->dst->priv;
  240. s->input_views[LEFT] = frame;
  241. return try_push_frame(inlink->dst);
  242. }
  243. static int filter_frame_right(AVFilterLink *inlink, AVFrame *frame)
  244. {
  245. FramepackContext *s = inlink->dst->priv;
  246. s->input_views[RIGHT] = frame;
  247. return try_push_frame(inlink->dst);
  248. }
  249. static int request_frame(AVFilterLink *outlink)
  250. {
  251. AVFilterContext *ctx = outlink->src;
  252. FramepackContext *s = ctx->priv;
  253. int ret, i;
  254. /* get a frame on the either input, stop as soon as a video ends */
  255. for (i = 0; i < 2; i++) {
  256. if (!s->input_views[i]) {
  257. ret = ff_request_frame(ctx->inputs[i]);
  258. if (ret < 0)
  259. return ret;
  260. }
  261. }
  262. return 0;
  263. }
  264. static int try_push_frame(AVFilterContext *ctx)
  265. {
  266. FramepackContext *s = ctx->priv;
  267. AVFilterLink *outlink = ctx->outputs[0];
  268. AVStereo3D *stereo;
  269. int ret, i;
  270. if (!(s->input_views[0] && s->input_views[1]))
  271. return 0;
  272. if (s->format == AV_STEREO3D_FRAMESEQUENCE) {
  273. if (s->double_pts == AV_NOPTS_VALUE)
  274. s->double_pts = s->input_views[LEFT]->pts;
  275. for (i = 0; i < 2; i++) {
  276. // set correct timestamps
  277. s->input_views[i]->pts = s->double_pts++;
  278. // set stereo3d side data
  279. stereo = av_stereo3d_create_side_data(s->input_views[i]);
  280. if (!stereo)
  281. return AVERROR(ENOMEM);
  282. stereo->type = s->format;
  283. // filter the frame and immediately relinquish its pointer
  284. ret = ff_filter_frame(outlink, s->input_views[i]);
  285. s->input_views[i] = NULL;
  286. if (ret < 0)
  287. return ret;
  288. }
  289. return ret;
  290. } else {
  291. AVFrame *dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  292. if (!dst)
  293. return AVERROR(ENOMEM);
  294. spatial_frame_pack(outlink, dst);
  295. // get any property from the original frame
  296. ret = av_frame_copy_props(dst, s->input_views[LEFT]);
  297. if (ret < 0) {
  298. av_frame_free(&dst);
  299. return ret;
  300. }
  301. for (i = 0; i < 2; i++)
  302. av_frame_free(&s->input_views[i]);
  303. // set stereo3d side data
  304. stereo = av_stereo3d_create_side_data(dst);
  305. if (!stereo) {
  306. av_frame_free(&dst);
  307. return AVERROR(ENOMEM);
  308. }
  309. stereo->type = s->format;
  310. return ff_filter_frame(outlink, dst);
  311. }
  312. }
  313. #define OFFSET(x) offsetof(FramepackContext, x)
  314. #define V AV_OPT_FLAG_VIDEO_PARAM
  315. static const AVOption framepack_options[] = {
  316. { "format", "Frame pack output format", OFFSET(format), AV_OPT_TYPE_INT,
  317. { .i64 = AV_STEREO3D_SIDEBYSIDE }, 0, INT_MAX, .flags = V, .unit = "format" },
  318. { "sbs", "Views are packed next to each other", 0, AV_OPT_TYPE_CONST,
  319. { .i64 = AV_STEREO3D_SIDEBYSIDE }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  320. { "tab", "Views are packed on top of each other", 0, AV_OPT_TYPE_CONST,
  321. { .i64 = AV_STEREO3D_TOPBOTTOM }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  322. { "frameseq", "Views are one after the other", 0, AV_OPT_TYPE_CONST,
  323. { .i64 = AV_STEREO3D_FRAMESEQUENCE }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  324. { "lines", "Views are interleaved by lines", 0, AV_OPT_TYPE_CONST,
  325. { .i64 = AV_STEREO3D_LINES }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  326. { "columns", "Views are interleaved by columns", 0, AV_OPT_TYPE_CONST,
  327. { .i64 = AV_STEREO3D_COLUMNS }, INT_MIN, INT_MAX, .flags = V, .unit = "format" },
  328. { NULL },
  329. };
  330. AVFILTER_DEFINE_CLASS(framepack);
  331. static const AVFilterPad framepack_inputs[] = {
  332. {
  333. .name = "left",
  334. .type = AVMEDIA_TYPE_VIDEO,
  335. .filter_frame = filter_frame_left,
  336. .needs_fifo = 1,
  337. },
  338. {
  339. .name = "right",
  340. .type = AVMEDIA_TYPE_VIDEO,
  341. .filter_frame = filter_frame_right,
  342. .needs_fifo = 1,
  343. },
  344. { NULL }
  345. };
  346. static const AVFilterPad framepack_outputs[] = {
  347. {
  348. .name = "packed",
  349. .type = AVMEDIA_TYPE_VIDEO,
  350. .config_props = config_output,
  351. .request_frame = request_frame,
  352. },
  353. { NULL }
  354. };
  355. AVFilter ff_vf_framepack = {
  356. .name = "framepack",
  357. .description = NULL_IF_CONFIG_SMALL("Generate a frame packed stereoscopic video."),
  358. .priv_size = sizeof(FramepackContext),
  359. .priv_class = &framepack_class,
  360. .query_formats = query_formats,
  361. .inputs = framepack_inputs,
  362. .outputs = framepack_outputs,
  363. .uninit = framepack_uninit,
  364. };