On Tue, Dec 3, 2013 at 9:43 PM, Anton Khirnov <[email protected]> wrote:
>
> On Thu, 28 Nov 2013 15:03:04 +0100, Vittorio Giovara
> <[email protected]> wrote:
>> ---
>> Changelog | 1 +
>> doc/filters.texi | 19 ++
>> libavfilter/Makefile | 1 +
>> libavfilter/allfilters.c | 1 +
>> libavfilter/version.h | 4 +-
>> libavfilter/vf_framepack.c | 488
>> ++++++++++++++++++++++++++++++++++++++++++++
>> 6 files changed, 512 insertions(+), 2 deletions(-)
>> create mode 100644 libavfilter/vf_framepack.c
>>
>> + // check input format
>> + if (s->pix_desc != right_desc) {
>> + av_log(inlink->dst, AV_LOG_ERROR,
>> + "Left and right color spaces differ (%s vs %s).\n",
>> + s->pix_desc->name, right_desc->name);
>> + return AVERROR_INVALIDDATA;
>> + }
>
> The inputs should be treated symmetrically, there is no guarantee in which
> order
> they are initialized. And the check is not needed anyway,
> ff_set_common_formats() makes sure the formats are the same on all pads.
neat, fixed and simplified.
[...]
>> +
>> + if (!interleaved) {
>> + for (i = 0; i < lines; i++) {
>> + memcpy(dstp, leftp, length);
>> + memcpy(dstp + length, rightp, length);
>> +
>> + dstp += dst->linesize[plane];
>> + leftp += s->left->linesize[plane];
>> + rightp += s->right->linesize[plane];
>> + }
>
> Can't av_image_copy() handle the non-interleaved case?
yes, I actually used av_image_copy_plane because that section is
inside a loop with all necessary data, anyway, and because using this
function directly allows me to skip copying any padded data.
>
>> + } else {
>> + for (i = 0; i < lines; i++) {
>> + int j;
>> + int k = 0;
>> +
>> + for (j = 0; j < length; j++) {
>> + dstp[k++] = leftp[j];
>> + dstp[k++] = rightp[j];
>> + }
>> +
>> + dstp += dst->linesize[plane];
>> + leftp += s->left->linesize[plane];
>> + rightp += s->right->linesize[plane];
>> + }
>> + }
>> + }
>> +
>> + return;
>> +}
>> +
>> +static void pack_topbottom_frame(FramepackContext *s,
>> + AVFrame *dst,
>> + int interleaved)
>> +{
>> + int plane, i;
>> + int step = interleaved ? 2 : 1;
>> + int length = s->left->width;
>> + int lines = s->left->height;
>> +
>> + for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
>> + const uint8_t *srcp;
>> + uint8_t *dstp;
>> +
>> + if (plane == 1 || plane == 2) {
>> + length = -(-s->left->width >> s->pix_desc->log2_chroma_w);
>> + lines = -(-s->left->height >> s->pix_desc->log2_chroma_h);
>> + }
>> +
>> + // copy first frame line by line
>> + srcp = s->left->data[plane];
>> + dstp = dst->data[plane];
>> + for (i = 0; i < lines; i ++) {
>> + memcpy(dstp, srcp, length);
>> + dstp += dst->linesize[plane] * step;
>> + srcp += s->left->linesize[plane];
>> + }
>> +
>> + // copy second frame line by line
>> + srcp = s->right->data[plane];
>> + if (interleaved) {
>> + // reset destination pointer and offset one line
>> + dstp = dst->data[plane] + dst->linesize[plane];
>> + }
>> + for (i = 0; i < lines; i ++) {
>> + memcpy(dstp, srcp, length);
>> + dstp += dst->linesize[plane] * step;
>> + srcp += s->right->linesize[plane];
>> + }
>> + }
>
> Can't this be replaced by av_image_copy()?
Yes, I made it similar to the above one.
>
>> +
>> + return;
>> +}
>> +
>> +static void pack_checkerboard_frame(FramepackContext *s, AVFrame *dst)
>> +{
>> + int plane, i;
>> + int length = s->left->width;
>> + int lines = s->left->height;
>> +
>> + for (plane = 0; plane < s->pix_desc->nb_components; plane++) {
>> + const uint8_t *leftp = s->left->data[plane];
>> + const uint8_t *rightp = s->right->data[plane];
>> + uint8_t *dstp = dst->data[plane];
>> +
>> + if (plane == 1 || plane == 2) {
>> + length = -(-s->left->width >> s->pix_desc->log2_chroma_w);
>> + lines = -(-s->left->height >> s->pix_desc->log2_chroma_h);
>> + }
>> +
>> + // alternatively copy one pixel, changing source at each line
>> + for (i = 0; i < lines; i++) {
>> + int k;
>> + for (k = 0; k < length; k += 2) {
>> + dstp[k] = i % 2 ? rightp[k] : leftp[k];
>> + dstp[k + 1] = i % 2 ? leftp[k + 1] : rightp[k + 1];
>> + }
>
> This code looks shady. Should k not run over input length * 2? Or does this
> packing lose half the resolution?
No, this packing loses half the resolution, I'll add a note in
config_output mentioning that.
[...]
>> +static int request_frame(AVFilterLink *outlink)
>> +{
>> + AVFilterContext *ctx = outlink->src;
>> + FramepackContext *s = ctx->priv;
>> + int ret, retl, retr;
>> + AVFrame *out;
>> + static uint64_t double_pts;
>
> static? really? =p
erm, moved to the context instead ^^.
>
>> +
>> + /* get a frame on the left input, on EOF reuse previous */
>> + if (!s->left) {
>> + retl = ff_request_frame(ctx->inputs[LEFT_VIEW]);
>> + if (retl < 0 && retl != AVERROR_EOF)
>> + return retl;
>> + }
>> + /* get a new frame on the right input, on EOF reuse previous */
>> + if (!s->right) {
>> + retr = ff_request_frame(ctx->inputs[RIGHT_VIEW]);
>> + if (retr < 0 && retr != AVERROR_EOF)
>> + return retr;
>> + }
>> + /* when both return values are EOF, it means that both
>> + * videos are fully processed and we can stop */
>> + if (retl == retr && retl == AVERROR_EOF)
>> + return retl;
>> +
>> + if (s->format == AV_STEREO3D_FRAMESEQUENCE) {
>> + AVFrame *cur;
>> + int i;
>> + double_pts = s->left->pts;
>> +
>> + for (i = 0; i < 2; i++) {
>> + cur = i == 0 ? s->left : s->right;
>> + out = av_frame_clone(cur);
>> + if (!out)
>> + return AVERROR(ENOMEM);
>> +
>> + out->pts = double_pts++;
>> + ret = set_side_data(out, s->format);
>> + if (ret < 0)
>> + return ret;
>> +
>> + ret = ff_filter_frame(outlink, out);
>> + if (ret < 0)
>> + return ret;
>> + }
>> + if (retl != AVERROR_EOF)
>> + av_frame_free(&s->left);
>> + if (retr != AVERROR_EOF)
>> + av_frame_free(&s->right);
>> + return ret;
>> + } else if (s->format == AV_STEREO3D_2D) {
>> + out = av_frame_clone(s->left);
>
> How is that supposed to work?
> The caller connects two streams, but only the left one is actually read?
> Looks awkward/hacky to me, perhaps it'd be better to have a separate filter.
It's a little awkward yeah, it was supposed to be the "default" mode
when no 3d was selected.
I'll go ahead remove it as it breaks the filter structure.
[...]
>> + ret = ff_filter_frame(outlink, out);
>> + if (ret < 0)
>> + return ret;
>> +
>> + // cleanup keeping a valid frame on EOF
>> + if (retl != AVERROR_EOF)
>> + av_frame_free(&s->left);
>> + if (retr != AVERROR_EOF)
>> + av_frame_free(&s->right);
>
> You could move the cleanup before ff_filter_frame, then just return
> ff_filter_frame()
Done.
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel