You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

483 lines
17KB

  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 "filters.h"
  33. #include "formats.h"
  34. #include "internal.h"
  35. #include "video.h"
  36. #define LEFT 0
  37. #define RIGHT 1
  38. typedef struct FramepackContext {
  39. const AVClass *class;
  40. int depth;
  41. const AVPixFmtDescriptor *pix_desc; ///< agreed pixel format
  42. enum AVStereo3DType format; ///< frame pack type output
  43. AVFrame *input_views[2]; ///< input frames
  44. } FramepackContext;
  45. static const enum AVPixelFormat formats_supported[] = {
  46. AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9,
  47. AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14,
  48. AV_PIX_FMT_GRAY16,
  49. AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P,
  50. AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P,
  51. AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P,
  52. AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P,
  53. AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P,
  54. AV_PIX_FMT_YUVJ411P,
  55. AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9,
  56. AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
  57. AV_PIX_FMT_YUV440P10,
  58. AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12,
  59. AV_PIX_FMT_YUV440P12,
  60. AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14,
  61. AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16,
  62. AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
  63. AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16,
  64. AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P,
  65. AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_YUVA444P16,
  66. AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA422P12, AV_PIX_FMT_YUVA422P16,
  67. AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA420P16,
  68. AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16,
  69. AV_PIX_FMT_NONE
  70. };
  71. static int query_formats(AVFilterContext *ctx)
  72. {
  73. // this will ensure that formats are the same on all pads
  74. AVFilterFormats *fmts_list = ff_make_format_list(formats_supported);
  75. if (!fmts_list)
  76. return AVERROR(ENOMEM);
  77. return ff_set_common_formats(ctx, fmts_list);
  78. }
  79. static av_cold void framepack_uninit(AVFilterContext *ctx)
  80. {
  81. FramepackContext *s = ctx->priv;
  82. // clean any leftover frame
  83. av_frame_free(&s->input_views[LEFT]);
  84. av_frame_free(&s->input_views[RIGHT]);
  85. }
  86. static int config_output(AVFilterLink *outlink)
  87. {
  88. AVFilterContext *ctx = outlink->src;
  89. FramepackContext *s = outlink->src->priv;
  90. int width = ctx->inputs[LEFT]->w;
  91. int height = ctx->inputs[LEFT]->h;
  92. AVRational time_base = ctx->inputs[LEFT]->time_base;
  93. AVRational frame_rate = ctx->inputs[LEFT]->frame_rate;
  94. // check size and fps match on the other input
  95. if (width != ctx->inputs[RIGHT]->w ||
  96. height != ctx->inputs[RIGHT]->h) {
  97. av_log(ctx, AV_LOG_ERROR,
  98. "Left and right sizes differ (%dx%d vs %dx%d).\n",
  99. width, height,
  100. ctx->inputs[RIGHT]->w, ctx->inputs[RIGHT]->h);
  101. return AVERROR_INVALIDDATA;
  102. } else if (av_cmp_q(time_base, ctx->inputs[RIGHT]->time_base) != 0) {
  103. av_log(ctx, AV_LOG_ERROR,
  104. "Left and right time bases differ (%d/%d vs %d/%d).\n",
  105. time_base.num, time_base.den,
  106. ctx->inputs[RIGHT]->time_base.num,
  107. ctx->inputs[RIGHT]->time_base.den);
  108. return AVERROR_INVALIDDATA;
  109. } else if (av_cmp_q(frame_rate, ctx->inputs[RIGHT]->frame_rate) != 0) {
  110. av_log(ctx, AV_LOG_ERROR,
  111. "Left and right framerates differ (%d/%d vs %d/%d).\n",
  112. frame_rate.num, frame_rate.den,
  113. ctx->inputs[RIGHT]->frame_rate.num,
  114. ctx->inputs[RIGHT]->frame_rate.den);
  115. return AVERROR_INVALIDDATA;
  116. }
  117. s->pix_desc = av_pix_fmt_desc_get(outlink->format);
  118. if (!s->pix_desc)
  119. return AVERROR_BUG;
  120. s->depth = s->pix_desc->comp[0].depth;
  121. // modify output properties as needed
  122. switch (s->format) {
  123. case AV_STEREO3D_FRAMESEQUENCE:
  124. time_base.den *= 2;
  125. frame_rate.num *= 2;
  126. break;
  127. case AV_STEREO3D_COLUMNS:
  128. case AV_STEREO3D_SIDEBYSIDE:
  129. width *= 2;
  130. break;
  131. case AV_STEREO3D_LINES:
  132. case AV_STEREO3D_TOPBOTTOM:
  133. height *= 2;
  134. break;
  135. default:
  136. av_log(ctx, AV_LOG_ERROR, "Unknown packing mode.");
  137. return AVERROR_INVALIDDATA;
  138. }
  139. outlink->w = width;
  140. outlink->h = height;
  141. outlink->time_base = time_base;
  142. outlink->frame_rate = frame_rate;
  143. return 0;
  144. }
  145. static void horizontal_frame_pack(AVFilterLink *outlink,
  146. AVFrame *out,
  147. int interleaved)
  148. {
  149. AVFilterContext *ctx = outlink->src;
  150. FramepackContext *s = ctx->priv;
  151. int i, plane;
  152. if (interleaved && s->depth <= 8) {
  153. const uint8_t *leftp = s->input_views[LEFT]->data[0];
  154. const uint8_t *rightp = s->input_views[RIGHT]->data[0];
  155. uint8_t *dstp = out->data[0];
  156. int length = out->width / 2;
  157. int lines = out->height;
  158. for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
  159. if (plane == 1 || plane == 2) {
  160. length = AV_CEIL_RSHIFT(out->width / 2, s->pix_desc->log2_chroma_w);
  161. lines = AV_CEIL_RSHIFT(out->height, s->pix_desc->log2_chroma_h);
  162. }
  163. for (i = 0; i < lines; i++) {
  164. int j;
  165. leftp = s->input_views[LEFT]->data[plane] +
  166. s->input_views[LEFT]->linesize[plane] * i;
  167. rightp = s->input_views[RIGHT]->data[plane] +
  168. s->input_views[RIGHT]->linesize[plane] * i;
  169. dstp = out->data[plane] + out->linesize[plane] * i;
  170. for (j = 0; j < length; j++) {
  171. // interpolate chroma as necessary
  172. if ((s->pix_desc->log2_chroma_w ||
  173. s->pix_desc->log2_chroma_h) &&
  174. (plane == 1 || plane == 2)) {
  175. *dstp++ = (*leftp + *rightp) / 2;
  176. *dstp++ = (*leftp + *rightp) / 2;
  177. } else {
  178. *dstp++ = *leftp;
  179. *dstp++ = *rightp;
  180. }
  181. leftp += 1;
  182. rightp += 1;
  183. }
  184. }
  185. }
  186. } else if (interleaved && s->depth > 8) {
  187. const uint16_t *leftp = (const uint16_t *)s->input_views[LEFT]->data[0];
  188. const uint16_t *rightp = (const uint16_t *)s->input_views[RIGHT]->data[0];
  189. uint16_t *dstp = (uint16_t *)out->data[0];
  190. int length = out->width / 2;
  191. int lines = out->height;
  192. for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
  193. if (plane == 1 || plane == 2) {
  194. length = AV_CEIL_RSHIFT(out->width / 2, s->pix_desc->log2_chroma_w);
  195. lines = AV_CEIL_RSHIFT(out->height, s->pix_desc->log2_chroma_h);
  196. }
  197. for (i = 0; i < lines; i++) {
  198. int j;
  199. leftp = (const uint16_t *)s->input_views[LEFT]->data[plane] +
  200. s->input_views[LEFT]->linesize[plane] * i / 2;
  201. rightp = (const uint16_t *)s->input_views[RIGHT]->data[plane] +
  202. s->input_views[RIGHT]->linesize[plane] * i / 2;
  203. dstp = (uint16_t *)out->data[plane] + out->linesize[plane] * i / 2;
  204. for (j = 0; j < length; j++) {
  205. // interpolate chroma as necessary
  206. if ((s->pix_desc->log2_chroma_w ||
  207. s->pix_desc->log2_chroma_h) &&
  208. (plane == 1 || plane == 2)) {
  209. *dstp++ = (*leftp + *rightp) / 2;
  210. *dstp++ = (*leftp + *rightp) / 2;
  211. } else {
  212. *dstp++ = *leftp;
  213. *dstp++ = *rightp;
  214. }
  215. leftp += 1;
  216. rightp += 1;
  217. }
  218. }
  219. }
  220. } else {
  221. for (i = 0; i < 2; i++) {
  222. const int psize = 1 + (s->depth > 8);
  223. const uint8_t *src[4];
  224. uint8_t *dst[4];
  225. int sub_w = psize * s->input_views[i]->width >> s->pix_desc->log2_chroma_w;
  226. src[0] = s->input_views[i]->data[0];
  227. src[1] = s->input_views[i]->data[1];
  228. src[2] = s->input_views[i]->data[2];
  229. dst[0] = out->data[0] + i * s->input_views[i]->width * psize;
  230. dst[1] = out->data[1] + i * sub_w;
  231. dst[2] = out->data[2] + i * sub_w;
  232. av_image_copy(dst, out->linesize, src, s->input_views[i]->linesize,
  233. s->input_views[i]->format,
  234. s->input_views[i]->width,
  235. s->input_views[i]->height);
  236. }
  237. }
  238. }
  239. static void vertical_frame_pack(AVFilterLink *outlink,
  240. AVFrame *out,
  241. int interleaved)
  242. {
  243. AVFilterContext *ctx = outlink->src;
  244. FramepackContext *s = ctx->priv;
  245. int i;
  246. for (i = 0; i < 2; i++) {
  247. const uint8_t *src[4];
  248. uint8_t *dst[4];
  249. int linesizes[4];
  250. int sub_h = s->input_views[i]->height >> s->pix_desc->log2_chroma_h;
  251. src[0] = s->input_views[i]->data[0];
  252. src[1] = s->input_views[i]->data[1];
  253. src[2] = s->input_views[i]->data[2];
  254. dst[0] = out->data[0] + i * out->linesize[0] *
  255. (interleaved + s->input_views[i]->height * (1 - interleaved));
  256. dst[1] = out->data[1] + i * out->linesize[1] *
  257. (interleaved + sub_h * (1 - interleaved));
  258. dst[2] = out->data[2] + i * out->linesize[2] *
  259. (interleaved + sub_h * (1 - interleaved));
  260. linesizes[0] = out->linesize[0] +
  261. interleaved * out->linesize[0];
  262. linesizes[1] = out->linesize[1] +
  263. interleaved * out->linesize[1];
  264. linesizes[2] = out->linesize[2] +
  265. interleaved * out->linesize[2];
  266. av_image_copy(dst, linesizes, src, s->input_views[i]->linesize,
  267. s->input_views[i]->format,
  268. s->input_views[i]->width,
  269. s->input_views[i]->height);
  270. }
  271. }
  272. static av_always_inline void spatial_frame_pack(AVFilterLink *outlink,
  273. AVFrame *dst)
  274. {
  275. AVFilterContext *ctx = outlink->src;
  276. FramepackContext *s = ctx->priv;
  277. switch (s->format) {
  278. case AV_STEREO3D_SIDEBYSIDE:
  279. horizontal_frame_pack(outlink, dst, 0);
  280. break;
  281. case AV_STEREO3D_COLUMNS:
  282. horizontal_frame_pack(outlink, dst, 1);
  283. break;
  284. case AV_STEREO3D_TOPBOTTOM:
  285. vertical_frame_pack(outlink, dst, 0);
  286. break;
  287. case AV_STEREO3D_LINES:
  288. vertical_frame_pack(outlink, dst, 1);
  289. break;
  290. }
  291. }
  292. static int try_push_frame(AVFilterContext *ctx)
  293. {
  294. FramepackContext *s = ctx->priv;
  295. AVFilterLink *outlink = ctx->outputs[0];
  296. AVStereo3D *stereo;
  297. int ret, i;
  298. if (!(s->input_views[0] && s->input_views[1]))
  299. return 0;
  300. if (s->format == AV_STEREO3D_FRAMESEQUENCE) {
  301. int64_t pts = s->input_views[0]->pts;
  302. for (i = 0; i < 2; i++) {
  303. // set correct timestamps
  304. if (pts != AV_NOPTS_VALUE)
  305. s->input_views[i]->pts = i == 0 ? pts * 2 : pts * 2 + av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
  306. // set stereo3d side data
  307. stereo = av_stereo3d_create_side_data(s->input_views[i]);
  308. if (!stereo)
  309. return AVERROR(ENOMEM);
  310. stereo->type = s->format;
  311. stereo->view = i == LEFT ? AV_STEREO3D_VIEW_LEFT
  312. : AV_STEREO3D_VIEW_RIGHT;
  313. // filter the frame and immediately relinquish its pointer
  314. ret = ff_filter_frame(outlink, s->input_views[i]);
  315. s->input_views[i] = NULL;
  316. if (ret < 0)
  317. return ret;
  318. }
  319. return ret;
  320. } else {
  321. AVFrame *dst = ff_get_video_buffer(outlink, outlink->w, outlink->h);
  322. if (!dst)
  323. return AVERROR(ENOMEM);
  324. spatial_frame_pack(outlink, dst);
  325. // get any property from the original frame
  326. ret = av_frame_copy_props(dst, s->input_views[LEFT]);
  327. if (ret < 0) {
  328. av_frame_free(&dst);
  329. return ret;
  330. }
  331. for (i = 0; i < 2; i++)
  332. av_frame_free(&s->input_views[i]);
  333. // set stereo3d side data
  334. stereo = av_stereo3d_create_side_data(dst);
  335. if (!stereo) {
  336. av_frame_free(&dst);
  337. return AVERROR(ENOMEM);
  338. }
  339. stereo->type = s->format;
  340. return ff_filter_frame(outlink, dst);
  341. }
  342. }
  343. static int activate(AVFilterContext *ctx)
  344. {
  345. AVFilterLink *outlink = ctx->outputs[0];
  346. FramepackContext *s = ctx->priv;
  347. int ret;
  348. FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx);
  349. if (!s->input_views[0]) {
  350. ret = ff_inlink_consume_frame(ctx->inputs[0], &s->input_views[0]);
  351. if (ret < 0)
  352. return ret;
  353. }
  354. if (!s->input_views[1]) {
  355. ret = ff_inlink_consume_frame(ctx->inputs[1], &s->input_views[1]);
  356. if (ret < 0)
  357. return ret;
  358. }
  359. if (s->input_views[0] && s->input_views[1])
  360. return try_push_frame(ctx);
  361. FF_FILTER_FORWARD_STATUS(ctx->inputs[0], outlink);
  362. FF_FILTER_FORWARD_STATUS(ctx->inputs[1], outlink);
  363. if (ff_outlink_frame_wanted(ctx->outputs[0]) &&
  364. !ff_outlink_get_status(ctx->inputs[0]) &&
  365. !s->input_views[0]) {
  366. ff_inlink_request_frame(ctx->inputs[0]);
  367. return 0;
  368. }
  369. if (ff_outlink_frame_wanted(ctx->outputs[0]) &&
  370. !ff_outlink_get_status(ctx->inputs[1]) &&
  371. !s->input_views[1]) {
  372. ff_inlink_request_frame(ctx->inputs[1]);
  373. return 0;
  374. }
  375. return FFERROR_NOT_READY;
  376. }
  377. #define OFFSET(x) offsetof(FramepackContext, x)
  378. #define VF AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
  379. static const AVOption framepack_options[] = {
  380. { "format", "Frame pack output format", OFFSET(format), AV_OPT_TYPE_INT,
  381. { .i64 = AV_STEREO3D_SIDEBYSIDE }, 0, INT_MAX, .flags = VF, .unit = "format" },
  382. { "sbs", "Views are packed next to each other", 0, AV_OPT_TYPE_CONST,
  383. { .i64 = AV_STEREO3D_SIDEBYSIDE }, INT_MIN, INT_MAX, .flags = VF, .unit = "format" },
  384. { "tab", "Views are packed on top of each other", 0, AV_OPT_TYPE_CONST,
  385. { .i64 = AV_STEREO3D_TOPBOTTOM }, INT_MIN, INT_MAX, .flags = VF, .unit = "format" },
  386. { "frameseq", "Views are one after the other", 0, AV_OPT_TYPE_CONST,
  387. { .i64 = AV_STEREO3D_FRAMESEQUENCE }, INT_MIN, INT_MAX, .flags = VF, .unit = "format" },
  388. { "lines", "Views are interleaved by lines", 0, AV_OPT_TYPE_CONST,
  389. { .i64 = AV_STEREO3D_LINES }, INT_MIN, INT_MAX, .flags = VF, .unit = "format" },
  390. { "columns", "Views are interleaved by columns", 0, AV_OPT_TYPE_CONST,
  391. { .i64 = AV_STEREO3D_COLUMNS }, INT_MIN, INT_MAX, .flags = VF, .unit = "format" },
  392. { NULL },
  393. };
  394. AVFILTER_DEFINE_CLASS(framepack);
  395. static const AVFilterPad framepack_inputs[] = {
  396. {
  397. .name = "left",
  398. .type = AVMEDIA_TYPE_VIDEO,
  399. },
  400. {
  401. .name = "right",
  402. .type = AVMEDIA_TYPE_VIDEO,
  403. },
  404. { NULL }
  405. };
  406. static const AVFilterPad framepack_outputs[] = {
  407. {
  408. .name = "packed",
  409. .type = AVMEDIA_TYPE_VIDEO,
  410. .config_props = config_output,
  411. },
  412. { NULL }
  413. };
  414. AVFilter ff_vf_framepack = {
  415. .name = "framepack",
  416. .description = NULL_IF_CONFIG_SMALL("Generate a frame packed stereoscopic video."),
  417. .priv_size = sizeof(FramepackContext),
  418. .priv_class = &framepack_class,
  419. .query_formats = query_formats,
  420. .inputs = framepack_inputs,
  421. .outputs = framepack_outputs,
  422. .activate = activate,
  423. .uninit = framepack_uninit,
  424. };