Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
a7d0e7ea
Commit
a7d0e7ea
authored
Jan 09, 2014
by
Vittorio Giovara
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lavfi: add framepack filter
parent
aa69cbc9
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
412 additions
and
1 deletion
+412
-1
Changelog
Changelog
+1
-0
filters.texi
doc/filters.texi
+45
-0
Makefile
libavfilter/Makefile
+1
-0
allfilters.c
libavfilter/allfilters.c
+1
-0
version.h
libavfilter/version.h
+1
-1
vf_framepack.c
libavfilter/vf_framepack.c
+363
-0
No files found.
Changelog
View file @
a7d0e7ea
...
...
@@ -54,6 +54,7 @@ version 10:
- png standalone parser
- WebP encoding via libwebp
- ATRAC3+ decoder
- framepack filter
version 9:
...
...
doc/filters.texi
View file @
a7d0e7ea
...
...
@@ -1252,6 +1252,51 @@ frames with a negative PTS.
@end table
@section framepack
Pack two different video streams into a stereoscopic video, setting proper
metadata on supported codecs. The two views should have the same size and
framerate and processing will stop when the shorter video ends. Please note
that you may conveniently adjust view properties with the @ref{scale} and
@ref{fps} filters.
This filter accepts the following named parameters:
@table @option
@item format
Desired packing format. Supported values are:
@table @option
@item sbs
Views are next to each other (default).
@item tab
Views are on top of each other.
@item lines
Views are packed by line.
@item columns
Views are eacked by column.
@item frameseq
Views are temporally interleaved.
@end table
@end table
Some examples follow:
@example
# Convert left and right views into a frame sequential video.
avconv -i LEFT -i RIGHT -filter_complex framepack=frameseq OUTPUT
# Convert views into a side-by-side video with the same output resolution as the input.
avconv -i LEFT -i RIGHT -filter_complex [0:v]scale=w=iw/2[left],[1:v]scale=w=iw/2[right],[left][right]framepack=sbs OUTPUT
@end example
@anchor{frei0r}
@section frei0r
...
...
libavfilter/Makefile
View file @
a7d0e7ea
...
...
@@ -54,6 +54,7 @@ OBJS-$(CONFIG_FADE_FILTER) += vf_fade.o
OBJS-$(CONFIG_FIELDORDER_FILTER)
+=
vf_fieldorder.o
OBJS-$(CONFIG_FORMAT_FILTER)
+=
vf_format.o
OBJS-$(CONFIG_FPS_FILTER)
+=
vf_fps.o
OBJS-$(CONFIG_FRAMEPACK_FILTER)
+=
vf_framepack.o
OBJS-$(CONFIG_FREI0R_FILTER)
+=
vf_frei0r.o
OBJS-$(CONFIG_GRADFUN_FILTER)
+=
vf_gradfun.o
OBJS-$(CONFIG_HFLIP_FILTER)
+=
vf_hflip.o
...
...
libavfilter/allfilters.c
View file @
a7d0e7ea
...
...
@@ -74,6 +74,7 @@ void avfilter_register_all(void)
REGISTER_FILTER
(
FIELDORDER
,
fieldorder
,
vf
);
REGISTER_FILTER
(
FORMAT
,
format
,
vf
);
REGISTER_FILTER
(
FPS
,
fps
,
vf
);
REGISTER_FILTER
(
FRAMEPACK
,
framepack
,
vf
);
REGISTER_FILTER
(
FREI0R
,
frei0r
,
vf
);
REGISTER_FILTER
(
GRADFUN
,
gradfun
,
vf
);
REGISTER_FILTER
(
HFLIP
,
hflip
,
vf
);
...
...
libavfilter/version.h
View file @
a7d0e7ea
...
...
@@ -30,7 +30,7 @@
#include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 4
#define LIBAVFILTER_VERSION_MINOR
0
#define LIBAVFILTER_VERSION_MINOR
1
#define LIBAVFILTER_VERSION_MICRO 0
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
...
...
libavfilter/vf_framepack.c
0 → 100644
View file @
a7d0e7ea
/*
* Copyright (c) 2013 Vittorio Giovara
*
* This file is part of Libav.
*
* Libav is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* Libav is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* Generate a frame packed video, by combining two views in a single surface.
*/
#include <string.h>
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#include "libavutil/rational.h"
#include "libavutil/stereo3d.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
#define LEFT 0
#define RIGHT 1
typedef
struct
FramepackContext
{
const
AVClass
*
class
;
const
AVPixFmtDescriptor
*
pix_desc
;
///< agreed pixel format
enum
AVStereo3DType
format
;
///< frame pack type output
AVFrame
*
input_views
[
2
];
///< input frames
int64_t
double_pts
;
///< new pts for frameseq mode
}
FramepackContext
;
static
const
enum
AVPixelFormat
formats_supported
[]
=
{
AV_PIX_FMT_YUV420P
,
AV_PIX_FMT_YUV422P
,
AV_PIX_FMT_YUV444P
,
AV_PIX_FMT_YUV410P
,
AV_PIX_FMT_YUVA420P
,
AV_PIX_FMT_YUVJ420P
,
AV_PIX_FMT_YUVJ422P
,
AV_PIX_FMT_YUVJ444P
,
AV_PIX_FMT_YUVJ440P
,
AV_PIX_FMT_NONE
};
static
int
query_formats
(
AVFilterContext
*
ctx
)
{
// this will ensure that formats are the same on all pads
ff_set_common_formats
(
ctx
,
ff_make_format_list
(
formats_supported
));
return
0
;
}
static
av_cold
void
framepack_uninit
(
AVFilterContext
*
ctx
)
{
FramepackContext
*
s
=
ctx
->
priv
;
// clean any leftover frame
av_frame_free
(
&
s
->
input_views
[
LEFT
]);
av_frame_free
(
&
s
->
input_views
[
RIGHT
]);
}
static
int
config_output
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
FramepackContext
*
s
=
outlink
->
src
->
priv
;
int
width
=
ctx
->
inputs
[
LEFT
]
->
w
;
int
height
=
ctx
->
inputs
[
LEFT
]
->
h
;
AVRational
time_base
=
ctx
->
inputs
[
LEFT
]
->
time_base
;
// check size and fps match on the other input
if
(
width
!=
ctx
->
inputs
[
RIGHT
]
->
w
||
height
!=
ctx
->
inputs
[
RIGHT
]
->
h
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Left and right sizes differ (%dx%d vs %dx%d).
\n
"
,
width
,
height
,
ctx
->
inputs
[
RIGHT
]
->
w
,
ctx
->
inputs
[
RIGHT
]
->
h
);
return
AVERROR_INVALIDDATA
;
}
else
if
(
av_cmp_q
(
time_base
,
ctx
->
inputs
[
RIGHT
]
->
time_base
)
!=
0
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Left and right framerates differ (%d/%d vs %d/%d).
\n
"
,
time_base
.
num
,
time_base
.
den
,
ctx
->
inputs
[
RIGHT
]
->
time_base
.
num
,
ctx
->
inputs
[
RIGHT
]
->
time_base
.
den
);
return
AVERROR_INVALIDDATA
;
}
s
->
pix_desc
=
av_pix_fmt_desc_get
(
outlink
->
format
);
if
(
!
s
->
pix_desc
)
return
AVERROR_BUG
;
// modify output properties as needed
switch
(
s
->
format
)
{
case
AV_STEREO3D_FRAMESEQUENCE
:
time_base
.
den
*=
2
;
s
->
double_pts
=
AV_NOPTS_VALUE
;
break
;
case
AV_STEREO3D_COLUMNS
:
case
AV_STEREO3D_SIDEBYSIDE
:
width
*=
2
;
break
;
case
AV_STEREO3D_LINES
:
case
AV_STEREO3D_TOPBOTTOM
:
height
*=
2
;
break
;
default:
av_log
(
ctx
,
AV_LOG_ERROR
,
"Unknown packing mode."
);
return
AVERROR_INVALIDDATA
;
}
outlink
->
w
=
width
;
outlink
->
h
=
height
;
outlink
->
time_base
=
time_base
;
return
0
;
}
static
void
horizontal_frame_pack
(
FramepackContext
*
s
,
AVFrame
*
dst
,
int
interleaved
)
{
int
plane
,
i
;
int
length
=
dst
->
width
/
2
;
int
lines
=
dst
->
height
;
for
(
plane
=
0
;
plane
<
s
->
pix_desc
->
nb_components
;
plane
++
)
{
const
uint8_t
*
leftp
=
s
->
input_views
[
LEFT
]
->
data
[
plane
];
const
uint8_t
*
rightp
=
s
->
input_views
[
RIGHT
]
->
data
[
plane
];
uint8_t
*
dstp
=
dst
->
data
[
plane
];
if
(
plane
==
1
||
plane
==
2
)
{
length
=
-
(
-
(
dst
->
width
/
2
)
>>
s
->
pix_desc
->
log2_chroma_w
);
lines
=
-
(
-
(
dst
->
height
)
>>
s
->
pix_desc
->
log2_chroma_h
);
}
if
(
interleaved
)
{
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
->
input_views
[
LEFT
]
->
linesize
[
plane
];
rightp
+=
s
->
input_views
[
RIGHT
]
->
linesize
[
plane
];
}
}
else
{
av_image_copy_plane
(
dst
->
data
[
plane
],
dst
->
linesize
[
plane
],
leftp
,
s
->
input_views
[
LEFT
]
->
linesize
[
plane
],
length
,
lines
);
av_image_copy_plane
(
dst
->
data
[
plane
]
+
length
,
dst
->
linesize
[
plane
],
rightp
,
s
->
input_views
[
RIGHT
]
->
linesize
[
plane
],
length
,
lines
);
}
}
}
static
void
vertical_frame_pack
(
FramepackContext
*
s
,
AVFrame
*
dst
,
int
interleaved
)
{
int
plane
,
offset
;
int
length
=
dst
->
width
;
int
lines
=
dst
->
height
/
2
;
for
(
plane
=
0
;
plane
<
s
->
pix_desc
->
nb_components
;
plane
++
)
{
if
(
plane
==
1
||
plane
==
2
)
{
length
=
-
(
-
(
dst
->
width
)
>>
s
->
pix_desc
->
log2_chroma_w
);
lines
=
-
(
-
(
dst
->
height
/
2
)
>>
s
->
pix_desc
->
log2_chroma_h
);
}
offset
=
interleaved
?
dst
->
linesize
[
plane
]
:
dst
->
linesize
[
plane
]
*
lines
;
av_image_copy_plane
(
dst
->
data
[
plane
],
dst
->
linesize
[
plane
]
<<
interleaved
,
s
->
input_views
[
LEFT
]
->
data
[
plane
],
s
->
input_views
[
LEFT
]
->
linesize
[
plane
],
length
,
lines
);
av_image_copy_plane
(
dst
->
data
[
plane
]
+
offset
,
dst
->
linesize
[
plane
]
<<
interleaved
,
s
->
input_views
[
RIGHT
]
->
data
[
plane
],
s
->
input_views
[
RIGHT
]
->
linesize
[
plane
],
length
,
lines
);
}
}
static
av_always_inline
void
spatial_frame_pack
(
FramepackContext
*
s
,
AVFrame
*
dst
)
{
switch
(
s
->
format
)
{
case
AV_STEREO3D_SIDEBYSIDE
:
horizontal_frame_pack
(
s
,
dst
,
0
);
break
;
case
AV_STEREO3D_COLUMNS
:
horizontal_frame_pack
(
s
,
dst
,
1
);
break
;
case
AV_STEREO3D_TOPBOTTOM
:
vertical_frame_pack
(
s
,
dst
,
0
);
break
;
case
AV_STEREO3D_LINES
:
vertical_frame_pack
(
s
,
dst
,
1
);
break
;
}
}
static
int
filter_frame_left
(
AVFilterLink
*
inlink
,
AVFrame
*
frame
)
{
FramepackContext
*
s
=
inlink
->
dst
->
priv
;
s
->
input_views
[
LEFT
]
=
frame
;
return
0
;
}
static
int
filter_frame_right
(
AVFilterLink
*
inlink
,
AVFrame
*
frame
)
{
FramepackContext
*
s
=
inlink
->
dst
->
priv
;
s
->
input_views
[
RIGHT
]
=
frame
;
return
0
;
}
static
int
request_frame
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
FramepackContext
*
s
=
ctx
->
priv
;
AVStereo3D
*
stereo
;
int
ret
,
i
;
/* get a frame on the either input, stop as soon as a video ends */
for
(
i
=
0
;
i
<
2
;
i
++
)
{
if
(
!
s
->
input_views
[
i
])
{
ret
=
ff_request_frame
(
ctx
->
inputs
[
i
]);
if
(
ret
<
0
)
return
ret
;
}
}
if
(
s
->
format
==
AV_STEREO3D_FRAMESEQUENCE
)
{
if
(
s
->
double_pts
==
AV_NOPTS_VALUE
)
s
->
double_pts
=
s
->
input_views
[
LEFT
]
->
pts
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
// set correct timestamps
s
->
input_views
[
i
]
->
pts
=
s
->
double_pts
++
;
// set stereo3d side data
stereo
=
av_stereo3d_create_side_data
(
s
->
input_views
[
i
]);
if
(
!
stereo
)
return
AVERROR
(
ENOMEM
);
stereo
->
type
=
s
->
format
;
// filter the frame and immediately relinquish its pointer
ret
=
ff_filter_frame
(
outlink
,
s
->
input_views
[
i
]);
s
->
input_views
[
i
]
=
NULL
;
if
(
ret
<
0
)
return
ret
;
}
return
ret
;
}
else
{
AVFrame
*
dst
=
ff_get_video_buffer
(
outlink
,
outlink
->
w
,
outlink
->
h
);
if
(
!
dst
)
return
AVERROR
(
ENOMEM
);
spatial_frame_pack
(
s
,
dst
);
// get any property from the original frame
ret
=
av_frame_copy_props
(
dst
,
s
->
input_views
[
LEFT
]);
if
(
ret
<
0
)
{
av_frame_free
(
&
dst
);
return
ret
;
}
for
(
i
=
0
;
i
<
2
;
i
++
)
av_frame_free
(
&
s
->
input_views
[
i
]);
// set stereo3d side data
stereo
=
av_stereo3d_create_side_data
(
dst
);
if
(
!
stereo
)
{
av_frame_free
(
&
dst
);
return
AVERROR
(
ENOMEM
);
}
stereo
->
type
=
s
->
format
;
return
ff_filter_frame
(
outlink
,
dst
);
}
}
#define OFFSET(x) offsetof(FramepackContext, x)
#define V AV_OPT_FLAG_VIDEO_PARAM
static
const
AVOption
options
[]
=
{
{
"format"
,
"Frame pack output format"
,
OFFSET
(
format
),
AV_OPT_TYPE_INT
,
{
.
i64
=
AV_STEREO3D_SIDEBYSIDE
},
0
,
INT_MAX
,
.
flags
=
V
,
.
unit
=
"format"
},
{
"sbs"
,
"Views are packed next to each other"
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
AV_STEREO3D_SIDEBYSIDE
},
INT_MIN
,
INT_MAX
,
.
flags
=
V
,
.
unit
=
"format"
},
{
"tab"
,
"Views are packed on top of each other"
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
AV_STEREO3D_TOPBOTTOM
},
INT_MIN
,
INT_MAX
,
.
flags
=
V
,
.
unit
=
"format"
},
{
"frameseq"
,
"Views are one after the other"
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
AV_STEREO3D_FRAMESEQUENCE
},
INT_MIN
,
INT_MAX
,
.
flags
=
V
,
.
unit
=
"format"
},
{
"lines"
,
"Views are interleaved by lines"
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
AV_STEREO3D_LINES
},
INT_MIN
,
INT_MAX
,
.
flags
=
V
,
.
unit
=
"format"
},
{
"columns"
,
"Views are interleaved by columns"
,
0
,
AV_OPT_TYPE_CONST
,
{
.
i64
=
AV_STEREO3D_COLUMNS
},
INT_MIN
,
INT_MAX
,
.
flags
=
V
,
.
unit
=
"format"
},
{
NULL
},
};
static
const
AVClass
framepack_class
=
{
.
class_name
=
"framepack"
,
.
item_name
=
av_default_item_name
,
.
option
=
options
,
.
version
=
LIBAVUTIL_VERSION_INT
,
};
static
const
AVFilterPad
framepack_inputs
[]
=
{
{
.
name
=
"left"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
filter_frame
=
filter_frame_left
,
.
needs_fifo
=
1
,
},
{
.
name
=
"right"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
filter_frame
=
filter_frame_right
,
.
needs_fifo
=
1
,
},
{
NULL
}
};
static
const
AVFilterPad
framepack_outputs
[]
=
{
{
.
name
=
"packed"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
config_props
=
config_output
,
.
request_frame
=
request_frame
,
},
{
NULL
}
};
AVFilter
ff_vf_framepack
=
{
.
name
=
"framepack"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Generate a frame packed stereoscopic video."
),
.
priv_size
=
sizeof
(
FramepackContext
),
.
priv_class
=
&
framepack_class
,
.
query_formats
=
query_formats
,
.
inputs
=
framepack_inputs
,
.
outputs
=
framepack_outputs
,
.
uninit
=
framepack_uninit
,
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment