The audio and video code paths were too different,
most of the decoding has been rewritten.
... | ... |
@@ -960,35 +960,8 @@ aevalsrc="0.1*sin(2*PI*(360-2.5/2)*t) : 0.1*sin(2*PI*(360+2.5/2)*t)" |
960 | 960 |
|
961 | 961 |
@section amovie |
962 | 962 |
|
963 |
-Read an audio stream from a movie container. |
|
964 |
- |
|
965 |
-It accepts the syntax: @var{movie_name}[:@var{options}] where |
|
966 |
-@var{movie_name} is the name of the resource to read (not necessarily |
|
967 |
-a file but also a device or a stream accessed through some protocol), |
|
968 |
-and @var{options} is an optional sequence of @var{key}=@var{value} |
|
969 |
-pairs, separated by ":". |
|
970 |
- |
|
971 |
-The description of the accepted options follows. |
|
972 |
- |
|
973 |
-@table @option |
|
974 |
- |
|
975 |
-@item format_name, f |
|
976 |
-Specify the format assumed for the movie to read, and can be either |
|
977 |
-the name of a container or an input device. If not specified the |
|
978 |
-format is guessed from @var{movie_name} or by probing. |
|
979 |
- |
|
980 |
-@item seek_point, sp |
|
981 |
-Specify the seek point in seconds, the frames will be output |
|
982 |
-starting from this seek point, the parameter is evaluated with |
|
983 |
-@code{av_strtod} so the numerical value may be suffixed by an IS |
|
984 |
-postfix. Default value is "0". |
|
985 |
- |
|
986 |
-@item stream_index, si |
|
987 |
-Specify the index of the audio stream to read. If the value is -1, |
|
988 |
-the best suited audio stream will be automatically selected. Default |
|
989 |
-value is "-1". |
|
990 |
- |
|
991 |
-@end table |
|
963 |
+This is the same as @ref{src_movie} source, except it selects an audio |
|
964 |
+stream by default. |
|
992 | 965 |
|
993 | 966 |
@section anullsrc |
994 | 967 |
|
... | ... |
@@ -3639,9 +3612,10 @@ to the pad with identifier "in". |
3639 | 3639 |
"color=c=red@@0.2:s=qcif:r=10 [color]; [in][color] overlay [out]" |
3640 | 3640 |
@end example |
3641 | 3641 |
|
3642 |
+@anchor{src_movie} |
|
3642 | 3643 |
@section movie |
3643 | 3644 |
|
3644 |
-Read a video stream from a movie container. |
|
3645 |
+Read audio and/or video stream(s) from a movie container. |
|
3645 | 3646 |
|
3646 | 3647 |
It accepts the syntax: @var{movie_name}[:@var{options}] where |
3647 | 3648 |
@var{movie_name} is the name of the resource to read (not necessarily |
... | ... |
@@ -3664,13 +3638,22 @@ starting from this seek point, the parameter is evaluated with |
3664 | 3664 |
@code{av_strtod} so the numerical value may be suffixed by an IS |
3665 | 3665 |
postfix. Default value is "0". |
3666 | 3666 |
|
3667 |
+@item streams, s |
|
3668 |
+Specifies the streams to read. Several streams can be specified, separated |
|
3669 |
+by "+". The source will then have as many outputs, in the same order. The |
|
3670 |
+syntax is explained in the @ref{Stream specifiers} chapter. Two special |
|
3671 |
+names, "dv" and "da" specify respectively the default (best suited) video |
|
3672 |
+and audio stream. Default is "dv", or "da" if the filter is called as |
|
3673 |
+"amovie". |
|
3674 |
+ |
|
3667 | 3675 |
@item stream_index, si |
3668 | 3676 |
Specifies the index of the video stream to read. If the value is -1, |
3669 | 3677 |
the best suited video stream will be automatically selected. Default |
3670 |
-value is "-1". |
|
3678 |
+value is "-1". Deprecated. If the filter is called "amovie", it will select |
|
3679 |
+audio instead of video. |
|
3671 | 3680 |
|
3672 | 3681 |
@item loop |
3673 |
-Specifies how many times to read the video stream in sequence. |
|
3682 |
+Specifies how many times to read the stream in sequence. |
|
3674 | 3683 |
If the value is less than 1, the stream will be read again and again. |
3675 | 3684 |
Default value is "1". |
3676 | 3685 |
|
... | ... |
@@ -3699,6 +3682,10 @@ movie=in.avi:seek_point=3.2, scale=180:-1, setpts=PTS-STARTPTS [movie]; |
3699 | 3699 |
movie=/dev/video0:f=video4linux2, scale=180:-1, setpts=PTS-STARTPTS [movie]; |
3700 | 3700 |
[in] setpts=PTS-STARTPTS, [movie] overlay=16:16 [out] |
3701 | 3701 |
|
3702 |
+# read the first video stream and the audio stream with id 0x81 from |
|
3703 |
+# dvd.vob; the video is connected to the pad named "video" and the audio is |
|
3704 |
+# connected to the pad named "audio": |
|
3705 |
+movie=dvd.vob:s=v:0+#0x81 [video] [audio] |
|
3702 | 3706 |
@end example |
3703 | 3707 |
|
3704 | 3708 |
@section mptestsrc |
... | ... |
@@ -25,15 +25,16 @@ |
25 | 25 |
* |
26 | 26 |
* @todo use direct rendering (no allocation of a new frame) |
27 | 27 |
* @todo support a PTS correction mechanism |
28 |
- * @todo support more than one output stream |
|
29 | 28 |
*/ |
30 | 29 |
|
31 | 30 |
/* #define DEBUG */ |
32 | 31 |
|
33 | 32 |
#include <float.h> |
34 | 33 |
#include "libavutil/avstring.h" |
34 |
+#include "libavutil/avassert.h" |
|
35 | 35 |
#include "libavutil/opt.h" |
36 | 36 |
#include "libavutil/imgutils.h" |
37 |
+#include "libavutil/timestamp.h" |
|
37 | 38 |
#include "libavformat/avformat.h" |
38 | 39 |
#include "audio.h" |
39 | 40 |
#include "avcodec.h" |
... | ... |
@@ -42,11 +43,10 @@ |
42 | 42 |
#include "internal.h" |
43 | 43 |
#include "video.h" |
44 | 44 |
|
45 |
-typedef enum { |
|
46 |
- STATE_DECODING, |
|
47 |
- STATE_FLUSHING, |
|
48 |
- STATE_DONE, |
|
49 |
-} MovieState; |
|
45 |
+typedef struct { |
|
46 |
+ AVStream *st; |
|
47 |
+ int done; |
|
48 |
+} MovieStream; |
|
50 | 49 |
|
51 | 50 |
typedef struct { |
52 | 51 |
/* common A/V fields */ |
... | ... |
@@ -55,22 +55,18 @@ typedef struct { |
55 | 55 |
double seek_point_d; |
56 | 56 |
char *format_name; |
57 | 57 |
char *file_name; |
58 |
- int stream_index; |
|
58 |
+ char *stream_specs; /**< user-provided list of streams, separated by + */ |
|
59 |
+ int stream_index; /**< for compatibility */ |
|
59 | 60 |
int loop_count; |
60 | 61 |
|
61 | 62 |
AVFormatContext *format_ctx; |
62 |
- AVCodecContext *codec_ctx; |
|
63 |
- MovieState state; |
|
63 |
+ int eof; |
|
64 |
+ AVPacket pkt, pkt0; |
|
64 | 65 |
AVFrame *frame; ///< video frame to store the decoded images in |
65 | 66 |
|
66 |
- /* video-only fields */ |
|
67 |
- int w, h; |
|
68 |
- AVFilterBufferRef *picref; |
|
69 |
- |
|
70 |
- /* audio-only fields */ |
|
71 |
- int bps; ///< bytes per sample |
|
72 |
- AVPacket pkt, pkt0; |
|
73 |
- AVFilterBufferRef *samplesref; |
|
67 |
+ int max_stream_index; /**< max stream # actually used for output */ |
|
68 |
+ MovieStream *st; /**< array of all streams, one per output */ |
|
69 |
+ int *out_index; /**< stream number -> output number map, or -1 */ |
|
74 | 70 |
} MovieContext; |
75 | 71 |
|
76 | 72 |
#define OFFSET(x) offsetof(MovieContext, x) |
... | ... |
@@ -78,8 +74,10 @@ typedef struct { |
78 | 78 |
static const AVOption movie_options[]= { |
79 | 79 |
{"format_name", "set format name", OFFSET(format_name), AV_OPT_TYPE_STRING, {.str = 0}, CHAR_MIN, CHAR_MAX }, |
80 | 80 |
{"f", "set format name", OFFSET(format_name), AV_OPT_TYPE_STRING, {.str = 0}, CHAR_MIN, CHAR_MAX }, |
81 |
-{"stream_index", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, {.dbl = -1}, -1, INT_MAX }, |
|
81 |
+{"streams", "set streams", OFFSET(stream_specs), AV_OPT_TYPE_STRING, {.str = 0}, CHAR_MAX, CHAR_MAX }, |
|
82 |
+{"s", "set streams", OFFSET(stream_specs), AV_OPT_TYPE_STRING, {.str = 0}, CHAR_MAX, CHAR_MAX }, |
|
82 | 83 |
{"si", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, {.dbl = -1}, -1, INT_MAX }, |
84 |
+{"stream_index", "set stream index", OFFSET(stream_index), AV_OPT_TYPE_INT, {.dbl = -1}, -1, INT_MAX }, |
|
83 | 85 |
{"seek_point", "set seekpoint (seconds)", OFFSET(seek_point_d), AV_OPT_TYPE_DOUBLE, {.dbl = 0}, 0, (INT64_MAX-1) / 1000000 }, |
84 | 86 |
{"sp", "set seekpoint (seconds)", OFFSET(seek_point_d), AV_OPT_TYPE_DOUBLE, {.dbl = 0}, 0, (INT64_MAX-1) / 1000000 }, |
85 | 87 |
{"loop", "set loop count", OFFSET(loop_count), AV_OPT_TYPE_INT, {.dbl = 1}, 0, INT_MAX }, |
... | ... |
@@ -88,14 +86,91 @@ static const AVOption movie_options[]= { |
88 | 88 |
|
89 | 89 |
AVFILTER_DEFINE_CLASS(movie); |
90 | 90 |
|
91 |
-static av_cold int movie_common_init(AVFilterContext *ctx, const char *args, |
|
92 |
- enum AVMediaType type) |
|
91 |
+static int movie_config_output_props(AVFilterLink *outlink); |
|
92 |
+static int movie_request_frame(AVFilterLink *outlink); |
|
93 |
+ |
|
94 |
+static AVStream *find_stream(void *log, AVFormatContext *avf, const char *spec) |
|
95 |
+{ |
|
96 |
+ int i, ret, already = 0, stream_id = -1; |
|
97 |
+ char type_char, dummy; |
|
98 |
+ AVStream *found = NULL; |
|
99 |
+ enum AVMediaType type; |
|
100 |
+ |
|
101 |
+ ret = sscanf(spec, "d%[av]%d%c", &type_char, &stream_id, &dummy); |
|
102 |
+ if (ret >= 1 && ret <= 2) { |
|
103 |
+ type = type_char == 'v' ? AVMEDIA_TYPE_VIDEO : AVMEDIA_TYPE_AUDIO; |
|
104 |
+ ret = av_find_best_stream(avf, type, stream_id, -1, NULL, 0); |
|
105 |
+ if (ret < 0) { |
|
106 |
+ av_log(log, AV_LOG_ERROR, "No %s stream with index '%d' found\n", |
|
107 |
+ av_get_media_type_string(type), stream_id); |
|
108 |
+ return NULL; |
|
109 |
+ } |
|
110 |
+ return avf->streams[ret]; |
|
111 |
+ } |
|
112 |
+ for (i = 0; i < avf->nb_streams; i++) { |
|
113 |
+ ret = avformat_match_stream_specifier(avf, avf->streams[i], spec); |
|
114 |
+ if (ret < 0) { |
|
115 |
+ av_log(log, AV_LOG_ERROR, |
|
116 |
+ "Invalid stream specifier \"%s\"\n", spec); |
|
117 |
+ return NULL; |
|
118 |
+ } |
|
119 |
+ if (!ret) |
|
120 |
+ continue; |
|
121 |
+ if (avf->streams[i]->discard != AVDISCARD_ALL) { |
|
122 |
+ already++; |
|
123 |
+ continue; |
|
124 |
+ } |
|
125 |
+ if (found) { |
|
126 |
+ av_log(log, AV_LOG_WARNING, |
|
127 |
+ "Ambiguous stream specifier \"%s\", using #%d\n", spec, i); |
|
128 |
+ break; |
|
129 |
+ } |
|
130 |
+ found = avf->streams[i]; |
|
131 |
+ } |
|
132 |
+ if (!found) { |
|
133 |
+ av_log(log, AV_LOG_WARNING, "Stream specifier \"%s\" %s\n", spec, |
|
134 |
+ already ? "matched only already used streams" : |
|
135 |
+ "did not match any stream"); |
|
136 |
+ return NULL; |
|
137 |
+ } |
|
138 |
+ if (found->codec->codec_type != AVMEDIA_TYPE_VIDEO && |
|
139 |
+ found->codec->codec_type != AVMEDIA_TYPE_AUDIO) { |
|
140 |
+ av_log(log, AV_LOG_ERROR, "Stream specifier \"%s\" matched a %s stream," |
|
141 |
+ "currently unsupported by libavfilter\n", spec, |
|
142 |
+ av_get_media_type_string(found->codec->codec_type)); |
|
143 |
+ return NULL; |
|
144 |
+ } |
|
145 |
+ return found; |
|
146 |
+} |
|
147 |
+ |
|
148 |
+static int open_stream(void *log, MovieStream *st) |
|
149 |
+{ |
|
150 |
+ AVCodec *codec; |
|
151 |
+ int ret; |
|
152 |
+ |
|
153 |
+ codec = avcodec_find_decoder(st->st->codec->codec_id); |
|
154 |
+ if (!codec) { |
|
155 |
+ av_log(log, AV_LOG_ERROR, "Failed to find any codec\n"); |
|
156 |
+ return AVERROR(EINVAL); |
|
157 |
+ } |
|
158 |
+ |
|
159 |
+ if ((ret = avcodec_open2(st->st->codec, codec, NULL)) < 0) { |
|
160 |
+ av_log(log, AV_LOG_ERROR, "Failed to open codec\n"); |
|
161 |
+ return ret; |
|
162 |
+ } |
|
163 |
+ |
|
164 |
+ return 0; |
|
165 |
+} |
|
166 |
+ |
|
167 |
+static av_cold int movie_init(AVFilterContext *ctx, const char *args) |
|
93 | 168 |
{ |
94 | 169 |
MovieContext *movie = ctx->priv; |
95 | 170 |
AVInputFormat *iformat = NULL; |
96 |
- AVCodec *codec; |
|
97 | 171 |
int64_t timestamp; |
98 |
- int ret; |
|
172 |
+ int nb_streams, ret, i; |
|
173 |
+ char default_streams[16], *stream_specs, *spec, *cursor; |
|
174 |
+ char name[16]; |
|
175 |
+ AVStream *st; |
|
99 | 176 |
|
100 | 177 |
movie->class = &movie_class; |
101 | 178 |
av_opt_set_defaults(movie); |
... | ... |
@@ -114,6 +189,23 @@ static av_cold int movie_common_init(AVFilterContext *ctx, const char *args, |
114 | 114 |
|
115 | 115 |
movie->seek_point = movie->seek_point_d * 1000000 + 0.5; |
116 | 116 |
|
117 |
+ stream_specs = movie->stream_specs; |
|
118 |
+ if (!stream_specs) { |
|
119 |
+ snprintf(default_streams, sizeof(default_streams), "d%c%d", |
|
120 |
+ !strcmp(ctx->filter->name, "amovie") ? 'a' : 'v', |
|
121 |
+ movie->stream_index); |
|
122 |
+ stream_specs = default_streams; |
|
123 |
+ } |
|
124 |
+ for (cursor = stream_specs, nb_streams = 1; *cursor; cursor++) |
|
125 |
+ if (*cursor == '+') |
|
126 |
+ nb_streams++; |
|
127 |
+ |
|
128 |
+ if (movie->loop_count != 1 && nb_streams != 1) { |
|
129 |
+ av_log(ctx, AV_LOG_ERROR, |
|
130 |
+ "Loop with several streams is currently unsupported\n"); |
|
131 |
+ return AVERROR_PATCHWELCOME; |
|
132 |
+ } |
|
133 |
+ |
|
117 | 134 |
av_register_all(); |
118 | 135 |
|
119 | 136 |
// Try to find the movie format (container) |
... | ... |
@@ -148,358 +240,358 @@ static av_cold int movie_common_init(AVFilterContext *ctx, const char *args, |
148 | 148 |
} |
149 | 149 |
} |
150 | 150 |
|
151 |
- /* select the media stream */ |
|
152 |
- if ((ret = av_find_best_stream(movie->format_ctx, type, |
|
153 |
- movie->stream_index, -1, NULL, 0)) < 0) { |
|
154 |
- av_log(ctx, AV_LOG_ERROR, "No %s stream with index '%d' found\n", |
|
155 |
- av_get_media_type_string(type), movie->stream_index); |
|
156 |
- return ret; |
|
151 |
+ for (i = 0; i < movie->format_ctx->nb_streams; i++) |
|
152 |
+ movie->format_ctx->streams[i]->discard = AVDISCARD_ALL; |
|
153 |
+ |
|
154 |
+ movie->st = av_calloc(nb_streams, sizeof(*movie->st)); |
|
155 |
+ if (!movie->st) |
|
156 |
+ return AVERROR(ENOMEM); |
|
157 |
+ |
|
158 |
+ for (i = 0; i < nb_streams; i++) { |
|
159 |
+ spec = av_strtok(stream_specs, "+", &cursor); |
|
160 |
+ if (!spec) |
|
161 |
+ return AVERROR_BUG; |
|
162 |
+ stream_specs = NULL; /* for next strtok */ |
|
163 |
+ st = find_stream(ctx, movie->format_ctx, spec); |
|
164 |
+ if (!st) |
|
165 |
+ return AVERROR(EINVAL); |
|
166 |
+ st->discard = AVDISCARD_DEFAULT; |
|
167 |
+ movie->st[i].st = st; |
|
168 |
+ movie->max_stream_index = FFMAX(movie->max_stream_index, st->index); |
|
157 | 169 |
} |
158 |
- movie->stream_index = ret; |
|
159 |
- movie->codec_ctx = movie->format_ctx->streams[movie->stream_index]->codec; |
|
160 |
- |
|
161 |
- /* |
|
162 |
- * So now we've got a pointer to the so-called codec context for our video |
|
163 |
- * stream, but we still have to find the actual codec and open it. |
|
164 |
- */ |
|
165 |
- codec = avcodec_find_decoder(movie->codec_ctx->codec_id); |
|
166 |
- if (!codec) { |
|
167 |
- av_log(ctx, AV_LOG_ERROR, "Failed to find any codec\n"); |
|
168 |
- return AVERROR(EINVAL); |
|
170 |
+ if (av_strtok(NULL, "+", &cursor)) |
|
171 |
+ return AVERROR_BUG; |
|
172 |
+ |
|
173 |
+ movie->out_index = av_calloc(movie->max_stream_index + 1, |
|
174 |
+ sizeof(*movie->out_index)); |
|
175 |
+ if (!movie->out_index) |
|
176 |
+ return AVERROR(ENOMEM); |
|
177 |
+ for (i = 0; i <= movie->max_stream_index; i++) |
|
178 |
+ movie->out_index[i] = -1; |
|
179 |
+ for (i = 0; i < nb_streams; i++) |
|
180 |
+ movie->out_index[movie->st[i].st->index] = i; |
|
181 |
+ |
|
182 |
+ for (i = 0; i < nb_streams; i++) { |
|
183 |
+ AVFilterPad pad = { 0 }; |
|
184 |
+ snprintf(name, sizeof(name), "out%d", i); |
|
185 |
+ pad.type = movie->st[i].st->codec->codec_type; |
|
186 |
+ pad.name = av_strdup(name); |
|
187 |
+ pad.config_props = movie_config_output_props; |
|
188 |
+ pad.request_frame = movie_request_frame; |
|
189 |
+ ff_insert_outpad(ctx, i, &pad); |
|
190 |
+ ret = open_stream(ctx, &movie->st[i]); |
|
191 |
+ if (ret < 0) |
|
192 |
+ return ret; |
|
169 | 193 |
} |
170 | 194 |
|
171 |
- if ((ret = avcodec_open2(movie->codec_ctx, codec, NULL)) < 0) { |
|
172 |
- av_log(ctx, AV_LOG_ERROR, "Failed to open codec\n"); |
|
173 |
- return ret; |
|
195 |
+ if (!(movie->frame = avcodec_alloc_frame()) ) { |
|
196 |
+ av_log(log, AV_LOG_ERROR, "Failed to alloc frame\n"); |
|
197 |
+ return AVERROR(ENOMEM); |
|
174 | 198 |
} |
175 | 199 |
|
176 | 200 |
av_log(ctx, AV_LOG_VERBOSE, "seek_point:%"PRIi64" format_name:%s file_name:%s stream_index:%d\n", |
177 | 201 |
movie->seek_point, movie->format_name, movie->file_name, |
178 | 202 |
movie->stream_index); |
179 | 203 |
|
180 |
- if (!(movie->frame = avcodec_alloc_frame()) ) { |
|
181 |
- av_log(ctx, AV_LOG_ERROR, "Failed to alloc frame\n"); |
|
182 |
- return AVERROR(ENOMEM); |
|
183 |
- } |
|
184 |
- |
|
185 | 204 |
return 0; |
186 | 205 |
} |
187 | 206 |
|
188 |
-static av_cold void movie_common_uninit(AVFilterContext *ctx) |
|
207 |
+static av_cold void movie_uninit(AVFilterContext *ctx) |
|
189 | 208 |
{ |
190 | 209 |
MovieContext *movie = ctx->priv; |
210 |
+ int i; |
|
191 | 211 |
|
192 |
- av_free(movie->file_name); |
|
193 |
- av_free(movie->format_name); |
|
194 |
- if (movie->codec_ctx) |
|
195 |
- avcodec_close(movie->codec_ctx); |
|
212 |
+ for (i = 0; i < ctx->nb_outputs; i++) { |
|
213 |
+ av_freep(&ctx->output_pads[i].name); |
|
214 |
+ if (movie->st[i].st) |
|
215 |
+ avcodec_close(movie->st[i].st->codec); |
|
216 |
+ } |
|
217 |
+ av_opt_free(movie); |
|
218 |
+ av_freep(&movie->file_name); |
|
219 |
+ av_freep(&movie->st); |
|
220 |
+ av_freep(&movie->out_index); |
|
221 |
+ av_freep(&movie->frame); |
|
196 | 222 |
if (movie->format_ctx) |
197 | 223 |
avformat_close_input(&movie->format_ctx); |
198 |
- |
|
199 |
- avfilter_unref_buffer(movie->picref); |
|
200 |
- av_freep(&movie->frame); |
|
201 |
- |
|
202 |
- avfilter_unref_buffer(movie->samplesref); |
|
203 | 224 |
} |
204 | 225 |
|
205 |
-#if CONFIG_MOVIE_FILTER |
|
206 |
- |
|
207 |
-static av_cold int movie_init(AVFilterContext *ctx, const char *args) |
|
226 |
+static int movie_query_formats(AVFilterContext *ctx) |
|
208 | 227 |
{ |
209 | 228 |
MovieContext *movie = ctx->priv; |
210 |
- int ret; |
|
229 |
+ int list[] = { 0, -1 }; |
|
230 |
+ int64_t list64[] = { 0, -1 }; |
|
231 |
+ int i; |
|
232 |
+ |
|
233 |
+ for (i = 0; i < ctx->nb_outputs; i++) { |
|
234 |
+ MovieStream *st = &movie->st[i]; |
|
235 |
+ AVCodecContext *c = st->st->codec; |
|
236 |
+ AVFilterLink *outlink = ctx->outputs[i]; |
|
237 |
+ |
|
238 |
+ switch (c->codec_type) { |
|
239 |
+ case AVMEDIA_TYPE_VIDEO: |
|
240 |
+ list[0] = c->pix_fmt; |
|
241 |
+ ff_formats_ref(ff_make_format_list(list), &outlink->in_formats); |
|
242 |
+ break; |
|
243 |
+ case AVMEDIA_TYPE_AUDIO: |
|
244 |
+ list[0] = c->sample_fmt; |
|
245 |
+ ff_formats_ref(ff_make_format_list(list), &outlink->in_formats); |
|
246 |
+ list[0] = c->sample_rate; |
|
247 |
+ ff_formats_ref(ff_make_format_list(list), &outlink->in_samplerates); |
|
248 |
+ list64[0] = c->channel_layout ? c->channel_layout : |
|
249 |
+ av_get_default_channel_layout(c->channels); |
|
250 |
+ ff_channel_layouts_ref(avfilter_make_format64_list(list64), |
|
251 |
+ &outlink->in_channel_layouts); |
|
252 |
+ break; |
|
253 |
+ } |
|
254 |
+ } |
|
211 | 255 |
|
212 |
- if ((ret = movie_common_init(ctx, args, AVMEDIA_TYPE_VIDEO)) < 0) |
|
213 |
- return ret; |
|
256 |
+ return 0; |
|
257 |
+} |
|
214 | 258 |
|
215 |
- movie->w = movie->codec_ctx->width; |
|
216 |
- movie->h = movie->codec_ctx->height; |
|
259 |
+static int movie_config_output_props(AVFilterLink *outlink) |
|
260 |
+{ |
|
261 |
+ AVFilterContext *ctx = outlink->src; |
|
262 |
+ MovieContext *movie = ctx->priv; |
|
263 |
+ unsigned out_id = FF_OUTLINK_IDX(outlink); |
|
264 |
+ MovieStream *st = &movie->st[out_id]; |
|
265 |
+ AVCodecContext *c = st->st->codec; |
|
266 |
+ |
|
267 |
+ outlink->time_base = st->st->time_base; |
|
268 |
+ |
|
269 |
+ switch (c->codec_type) { |
|
270 |
+ case AVMEDIA_TYPE_VIDEO: |
|
271 |
+ outlink->w = c->width; |
|
272 |
+ outlink->h = c->height; |
|
273 |
+ outlink->frame_rate = st->st->r_frame_rate; |
|
274 |
+ break; |
|
275 |
+ case AVMEDIA_TYPE_AUDIO: |
|
276 |
+ break; |
|
277 |
+ } |
|
217 | 278 |
|
218 | 279 |
return 0; |
219 | 280 |
} |
220 | 281 |
|
221 |
-static int movie_query_formats(AVFilterContext *ctx) |
|
282 |
+static AVFilterBufferRef *frame_to_buf(enum AVMediaType type, AVFrame *frame, |
|
283 |
+ AVFilterLink *outlink) |
|
222 | 284 |
{ |
223 |
- MovieContext *movie = ctx->priv; |
|
224 |
- enum PixelFormat pix_fmts[] = { movie->codec_ctx->pix_fmt, PIX_FMT_NONE }; |
|
285 |
+ AVFilterBufferRef *buf, *copy; |
|
286 |
+ |
|
287 |
+ buf = avfilter_get_buffer_ref_from_frame(type, frame, |
|
288 |
+ AV_PERM_WRITE | |
|
289 |
+ AV_PERM_PRESERVE | |
|
290 |
+ AV_PERM_REUSE2); |
|
291 |
+ if (!buf) |
|
292 |
+ return NULL; |
|
293 |
+ buf->pts = av_frame_get_best_effort_timestamp(frame); |
|
294 |
+ copy = ff_copy_buffer_ref(outlink, buf); |
|
295 |
+ if (!copy) |
|
296 |
+ return NULL; |
|
297 |
+ buf->buf->data[0] = NULL; /* it belongs to the frame */ |
|
298 |
+ avfilter_unref_buffer(buf); |
|
299 |
+ return copy; |
|
300 |
+} |
|
225 | 301 |
|
226 |
- ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); |
|
227 |
- return 0; |
|
302 |
+static char *describe_bufref_to_str(char *dst, size_t dst_size, |
|
303 |
+ AVFilterBufferRef *buf, |
|
304 |
+ AVFilterLink *link) |
|
305 |
+{ |
|
306 |
+ switch (buf->type) { |
|
307 |
+ case AVMEDIA_TYPE_VIDEO: |
|
308 |
+ snprintf(dst, dst_size, |
|
309 |
+ "video pts:%s time:%s pos:%"PRId64" size:%dx%d aspect:%d/%d", |
|
310 |
+ av_ts2str(buf->pts), av_ts2timestr(buf->pts, &link->time_base), |
|
311 |
+ buf->pos, buf->video->w, buf->video->h, |
|
312 |
+ buf->video->sample_aspect_ratio.num, |
|
313 |
+ buf->video->sample_aspect_ratio.den); |
|
314 |
+ break; |
|
315 |
+ case AVMEDIA_TYPE_AUDIO: |
|
316 |
+ snprintf(dst, dst_size, |
|
317 |
+ "audio pts:%s time:%s pos:%"PRId64" samples:%d", |
|
318 |
+ av_ts2str(buf->pts), av_ts2timestr(buf->pts, &link->time_base), |
|
319 |
+ buf->pos, buf->audio->nb_samples); |
|
320 |
+ break; |
|
321 |
+ default: |
|
322 |
+ snprintf(dst, dst_size, "%s BUG", av_get_media_type_string(buf->type)); |
|
323 |
+ break; |
|
324 |
+ } |
|
325 |
+ return dst; |
|
228 | 326 |
} |
229 | 327 |
|
230 |
-static int movie_config_output_props(AVFilterLink *outlink) |
|
328 |
+#define describe_bufref(buf, link) \ |
|
329 |
+ describe_bufref_to_str((char[1024]){0}, 1024, buf, link) |
|
330 |
+ |
|
331 |
+static int rewind_file(AVFilterContext *ctx) |
|
231 | 332 |
{ |
232 |
- MovieContext *movie = outlink->src->priv; |
|
333 |
+ MovieContext *movie = ctx->priv; |
|
334 |
+ int64_t timestamp = movie->seek_point; |
|
335 |
+ int ret, i; |
|
233 | 336 |
|
234 |
- outlink->w = movie->w; |
|
235 |
- outlink->h = movie->h; |
|
236 |
- outlink->time_base = movie->format_ctx->streams[movie->stream_index]->time_base; |
|
337 |
+ if (movie->format_ctx->start_time != AV_NOPTS_VALUE) |
|
338 |
+ timestamp += movie->format_ctx->start_time; |
|
339 |
+ ret = av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD); |
|
340 |
+ if (ret < 0) { |
|
341 |
+ av_log(ctx, AV_LOG_ERROR, "Unable to loop: %s\n", av_err2str(ret)); |
|
342 |
+ movie->loop_count = 1; /* do not try again */ |
|
343 |
+ return ret; |
|
344 |
+ } |
|
237 | 345 |
|
346 |
+ for (i = 0; i < ctx->nb_outputs; i++) { |
|
347 |
+ avcodec_flush_buffers(movie->st[i].st->codec); |
|
348 |
+ movie->st[i].done = 0; |
|
349 |
+ } |
|
350 |
+ movie->eof = 0; |
|
238 | 351 |
return 0; |
239 | 352 |
} |
240 | 353 |
|
241 |
-static int movie_get_frame(AVFilterLink *outlink) |
|
354 |
+/** |
|
355 |
+ * Try to push a frame to the requested output. |
|
356 |
+ * |
|
357 |
+ * @return 1 if a frame was pushed on the requested output, |
|
358 |
+ * 0 if another attempt is possible, |
|
359 |
+ * <0 AVERROR code |
|
360 |
+ */ |
|
361 |
+static int movie_push_frame(AVFilterContext *ctx, unsigned out_id) |
|
242 | 362 |
{ |
243 |
- MovieContext *movie = outlink->src->priv; |
|
244 |
- AVPacket pkt; |
|
245 |
- int ret = 0, frame_decoded; |
|
246 |
- AVStream *st = movie->format_ctx->streams[movie->stream_index]; |
|
247 |
- |
|
248 |
- if (movie->state == STATE_DONE) |
|
249 |
- return 0; |
|
250 |
- |
|
251 |
- while (1) { |
|
252 |
- if (movie->state == STATE_DECODING) { |
|
253 |
- ret = av_read_frame(movie->format_ctx, &pkt); |
|
254 |
- if (ret == AVERROR_EOF) { |
|
255 |
- int64_t timestamp; |
|
363 |
+ MovieContext *movie = ctx->priv; |
|
364 |
+ AVPacket *pkt = &movie->pkt; |
|
365 |
+ MovieStream *st; |
|
366 |
+ int ret, got_frame = 0, pkt_out_id; |
|
367 |
+ AVFilterLink *outlink; |
|
368 |
+ AVFilterBufferRef *buf; |
|
369 |
+ |
|
370 |
+ if (!pkt->size) { |
|
371 |
+ if (movie->eof) { |
|
372 |
+ if (movie->st[out_id].done) { |
|
256 | 373 |
if (movie->loop_count != 1) { |
257 |
- timestamp = movie->seek_point; |
|
258 |
- if (movie->format_ctx->start_time != AV_NOPTS_VALUE) |
|
259 |
- timestamp += movie->format_ctx->start_time; |
|
260 |
- if (av_seek_frame(movie->format_ctx, -1, timestamp, AVSEEK_FLAG_BACKWARD) < 0) { |
|
261 |
- movie->state = STATE_FLUSHING; |
|
262 |
- } else if (movie->loop_count>1) |
|
263 |
- movie->loop_count--; |
|
264 |
- continue; |
|
265 |
- } else { |
|
266 |
- movie->state = STATE_FLUSHING; |
|
374 |
+ ret = rewind_file(ctx); |
|
375 |
+ if (ret < 0) |
|
376 |
+ return ret; |
|
377 |
+ movie->loop_count -= movie->loop_count > 1; |
|
378 |
+ av_log(ctx, AV_LOG_VERBOSE, "Stream finished, looping.\n"); |
|
379 |
+ return 0; /* retry */ |
|
267 | 380 |
} |
268 |
- } else if (ret < 0) |
|
269 |
- break; |
|
270 |
- } |
|
271 |
- |
|
272 |
- // Is this a packet from the video stream? |
|
273 |
- if (pkt.stream_index == movie->stream_index || movie->state == STATE_FLUSHING) { |
|
274 |
- avcodec_decode_video2(movie->codec_ctx, movie->frame, &frame_decoded, &pkt); |
|
275 |
- |
|
276 |
- if (frame_decoded) { |
|
277 |
- /* FIXME: avoid the memcpy */ |
|
278 |
- movie->picref = ff_get_video_buffer(outlink, AV_PERM_WRITE | AV_PERM_PRESERVE | |
|
279 |
- AV_PERM_REUSE2, outlink->w, outlink->h); |
|
280 |
- av_image_copy(movie->picref->data, movie->picref->linesize, |
|
281 |
- (void*)movie->frame->data, movie->frame->linesize, |
|
282 |
- movie->picref->format, outlink->w, outlink->h); |
|
283 |
- avfilter_copy_frame_props(movie->picref, movie->frame); |
|
284 |
- |
|
285 |
- /* FIXME: use a PTS correction mechanism as that in |
|
286 |
- * ffplay.c when some API will be available for that */ |
|
287 |
- /* use pkt_dts if pkt_pts is not available */ |
|
288 |
- movie->picref->pts = movie->frame->pkt_pts == AV_NOPTS_VALUE ? |
|
289 |
- movie->frame->pkt_dts : movie->frame->pkt_pts; |
|
290 |
- |
|
291 |
- if (!movie->frame->sample_aspect_ratio.num) |
|
292 |
- movie->picref->video->sample_aspect_ratio = st->sample_aspect_ratio; |
|
293 |
- av_dlog(outlink->src, |
|
294 |
- "movie_get_frame(): file:'%s' pts:%"PRId64" time:%lf pos:%"PRId64" aspect:%d/%d\n", |
|
295 |
- movie->file_name, movie->picref->pts, |
|
296 |
- (double)movie->picref->pts * av_q2d(st->time_base), |
|
297 |
- movie->picref->pos, |
|
298 |
- movie->picref->video->sample_aspect_ratio.num, |
|
299 |
- movie->picref->video->sample_aspect_ratio.den); |
|
300 |
- // We got it. Free the packet since we are returning |
|
301 |
- av_free_packet(&pkt); |
|
302 |
- |
|
303 |
- return 0; |
|
304 |
- } else if (movie->state == STATE_FLUSHING) { |
|
305 |
- movie->state = STATE_DONE; |
|
306 |
- av_free_packet(&pkt); |
|
307 | 381 |
return AVERROR_EOF; |
308 | 382 |
} |
383 |
+ /* packet is already ready for flushing */ |
|
384 |
+ } else { |
|
385 |
+ ret = av_read_frame(movie->format_ctx, &movie->pkt0); |
|
386 |
+ if (ret < 0) { |
|
387 |
+ av_init_packet(&movie->pkt0); /* ready for flushing */ |
|
388 |
+ *pkt = movie->pkt0; |
|
389 |
+ if (ret == AVERROR_EOF) { |
|
390 |
+ movie->eof = 1; |
|
391 |
+ return 0; /* start flushing */ |
|
392 |
+ } |
|
393 |
+ return ret; |
|
394 |
+ } |
|
395 |
+ *pkt = movie->pkt0; |
|
309 | 396 |
} |
310 |
- // Free the packet that was allocated by av_read_frame |
|
311 |
- av_free_packet(&pkt); |
|
312 | 397 |
} |
313 | 398 |
|
314 |
- return ret; |
|
399 |
+ pkt_out_id = pkt->stream_index > movie->max_stream_index ? -1 : |
|
400 |
+ movie->out_index[pkt->stream_index]; |
|
401 |
+ if (pkt_out_id < 0) { |
|
402 |
+ av_free_packet(&movie->pkt0); |
|
403 |
+ pkt->size = 0; /* ready for next run */ |
|
404 |
+ pkt->data = NULL; |
|
405 |
+ return 0; |
|
406 |
+ } |
|
407 |
+ st = &movie->st[pkt_out_id]; |
|
408 |
+ outlink = ctx->outputs[pkt_out_id]; |
|
409 |
+ |
|
410 |
+ switch (st->st->codec->codec_type) { |
|
411 |
+ case AVMEDIA_TYPE_VIDEO: |
|
412 |
+ ret = avcodec_decode_video2(st->st->codec, movie->frame, &got_frame, pkt); |
|
413 |
+ break; |
|
414 |
+ case AVMEDIA_TYPE_AUDIO: |
|
415 |
+ ret = avcodec_decode_audio4(st->st->codec, movie->frame, &got_frame, pkt); |
|
416 |
+ break; |
|
417 |
+ default: |
|
418 |
+ ret = AVERROR(ENOSYS); |
|
419 |
+ break; |
|
420 |
+ } |
|
421 |
+ if (ret < 0) { |
|
422 |
+ av_log(ctx, AV_LOG_WARNING, "Decode error: %s\n", av_err2str(ret)); |
|
423 |
+ return 0; |
|
424 |
+ } |
|
425 |
+ if (!ret) |
|
426 |
+ ret = pkt->size; |
|
427 |
+ |
|
428 |
+ pkt->data += ret; |
|
429 |
+ pkt->size -= ret; |
|
430 |
+ if (pkt->size <= 0) { |
|
431 |
+ av_free_packet(&movie->pkt0); |
|
432 |
+ pkt->size = 0; /* ready for next run */ |
|
433 |
+ pkt->data = NULL; |
|
434 |
+ } |
|
435 |
+ if (!got_frame) { |
|
436 |
+ if (!ret) |
|
437 |
+ st->done = 1; |
|
438 |
+ return 0; |
|
439 |
+ } |
|
440 |
+ |
|
441 |
+ buf = frame_to_buf(st->st->codec->codec_type, movie->frame, outlink); |
|
442 |
+ if (!buf) |
|
443 |
+ return AVERROR(ENOMEM); |
|
444 |
+ av_dlog(ctx, "movie_push_frame(): file:'%s' %s\n", movie->file_name, |
|
445 |
+ describe_bufref(buf, outlink)); |
|
446 |
+ switch (st->st->codec->codec_type) { |
|
447 |
+ case AVMEDIA_TYPE_VIDEO: |
|
448 |
+ if (!movie->frame->sample_aspect_ratio.num) |
|
449 |
+ buf->video->sample_aspect_ratio = st->st->sample_aspect_ratio; |
|
450 |
+ ff_start_frame(outlink, buf); |
|
451 |
+ ff_draw_slice(outlink, 0, outlink->h, 1); |
|
452 |
+ ff_end_frame(outlink); |
|
453 |
+ break; |
|
454 |
+ case AVMEDIA_TYPE_AUDIO: |
|
455 |
+ ff_filter_samples(outlink, buf); |
|
456 |
+ break; |
|
457 |
+ } |
|
458 |
+ |
|
459 |
+ return pkt_out_id == out_id; |
|
315 | 460 |
} |
316 | 461 |
|
317 | 462 |
static int movie_request_frame(AVFilterLink *outlink) |
318 | 463 |
{ |
319 |
- AVFilterBufferRef *outpicref; |
|
320 |
- MovieContext *movie = outlink->src->priv; |
|
464 |
+ AVFilterContext *ctx = outlink->src; |
|
465 |
+ unsigned out_id = FF_OUTLINK_IDX(outlink); |
|
321 | 466 |
int ret; |
322 | 467 |
|
323 |
- if (movie->state == STATE_DONE) |
|
324 |
- return AVERROR_EOF; |
|
325 |
- if ((ret = movie_get_frame(outlink)) < 0) |
|
326 |
- return ret; |
|
327 |
- |
|
328 |
- outpicref = avfilter_ref_buffer(movie->picref, ~0); |
|
329 |
- if (!outpicref) { |
|
330 |
- ret = AVERROR(ENOMEM); |
|
331 |
- goto fail; |
|
468 |
+ while (1) { |
|
469 |
+ ret = movie_push_frame(ctx, out_id); |
|
470 |
+ if (ret) |
|
471 |
+ return FFMIN(ret, 0); |
|
332 | 472 |
} |
333 |
- |
|
334 |
- ret = ff_start_frame(outlink, outpicref); |
|
335 |
- if (ret < 0) |
|
336 |
- goto fail; |
|
337 |
- |
|
338 |
- ret = ff_draw_slice(outlink, 0, outlink->h, 1); |
|
339 |
- if (ret < 0) |
|
340 |
- goto fail; |
|
341 |
- |
|
342 |
- ret = ff_end_frame(outlink); |
|
343 |
-fail: |
|
344 |
- avfilter_unref_bufferp(&movie->picref); |
|
345 |
- |
|
346 |
- return ret; |
|
347 | 473 |
} |
348 | 474 |
|
475 |
+#if CONFIG_MOVIE_FILTER |
|
476 |
+ |
|
349 | 477 |
AVFilter avfilter_vsrc_movie = { |
350 | 478 |
.name = "movie", |
351 | 479 |
.description = NULL_IF_CONFIG_SMALL("Read from a movie source."), |
352 | 480 |
.priv_size = sizeof(MovieContext), |
353 | 481 |
.init = movie_init, |
354 |
- .uninit = movie_common_uninit, |
|
482 |
+ .uninit = movie_uninit, |
|
355 | 483 |
.query_formats = movie_query_formats, |
356 | 484 |
|
357 | 485 |
.inputs = (const AVFilterPad[]) {{ .name = NULL }}, |
358 |
- .outputs = (const AVFilterPad[]) {{ .name = "default", |
|
359 |
- .type = AVMEDIA_TYPE_VIDEO, |
|
360 |
- .request_frame = movie_request_frame, |
|
361 |
- .config_props = movie_config_output_props, }, |
|
362 |
- { .name = NULL}}, |
|
486 |
+ .outputs = (const AVFilterPad[]) {{ .name = NULL }}, |
|
363 | 487 |
}; |
364 | 488 |
|
365 | 489 |
#endif /* CONFIG_MOVIE_FILTER */ |
366 | 490 |
|
367 | 491 |
#if CONFIG_AMOVIE_FILTER |
368 | 492 |
|
369 |
-static av_cold int amovie_init(AVFilterContext *ctx, const char *args) |
|
370 |
-{ |
|
371 |
- MovieContext *movie = ctx->priv; |
|
372 |
- int ret; |
|
373 |
- |
|
374 |
- if ((ret = movie_common_init(ctx, args, AVMEDIA_TYPE_AUDIO)) < 0) |
|
375 |
- return ret; |
|
376 |
- |
|
377 |
- movie->bps = av_get_bytes_per_sample(movie->codec_ctx->sample_fmt); |
|
378 |
- return 0; |
|
379 |
-} |
|
380 |
- |
|
381 |
-static int amovie_query_formats(AVFilterContext *ctx) |
|
382 |
-{ |
|
383 |
- MovieContext *movie = ctx->priv; |
|
384 |
- AVCodecContext *c = movie->codec_ctx; |
|
385 |
- |
|
386 |
- enum AVSampleFormat sample_fmts[] = { c->sample_fmt, -1 }; |
|
387 |
- int sample_rates[] = { c->sample_rate, -1 }; |
|
388 |
- int64_t chlayouts[] = { c->channel_layout ? c->channel_layout : |
|
389 |
- av_get_default_channel_layout(c->channels), -1 }; |
|
390 |
- |
|
391 |
- ff_set_common_formats (ctx, ff_make_format_list(sample_fmts)); |
|
392 |
- ff_set_common_samplerates (ctx, ff_make_format_list(sample_rates)); |
|
393 |
- ff_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts)); |
|
394 |
- |
|
395 |
- return 0; |
|
396 |
-} |
|
397 |
- |
|
398 |
-static int amovie_config_output_props(AVFilterLink *outlink) |
|
399 |
-{ |
|
400 |
- MovieContext *movie = outlink->src->priv; |
|
401 |
- AVCodecContext *c = movie->codec_ctx; |
|
402 |
- |
|
403 |
- outlink->sample_rate = c->sample_rate; |
|
404 |
- outlink->time_base = movie->format_ctx->streams[movie->stream_index]->time_base; |
|
405 |
- |
|
406 |
- return 0; |
|
407 |
-} |
|
408 |
- |
|
409 |
-static int amovie_get_samples(AVFilterLink *outlink) |
|
410 |
-{ |
|
411 |
- MovieContext *movie = outlink->src->priv; |
|
412 |
- AVPacket pkt; |
|
413 |
- int ret, got_frame = 0; |
|
414 |
- |
|
415 |
- if (!movie->pkt.size && movie->state == STATE_DONE) |
|
416 |
- return AVERROR_EOF; |
|
417 |
- |
|
418 |
- /* check for another frame, in case the previous one was completely consumed */ |
|
419 |
- if (!movie->pkt.size) { |
|
420 |
- while ((ret = av_read_frame(movie->format_ctx, &pkt)) >= 0) { |
|
421 |
- // Is this a packet from the selected stream? |
|
422 |
- if (pkt.stream_index != movie->stream_index) { |
|
423 |
- av_free_packet(&pkt); |
|
424 |
- continue; |
|
425 |
- } else { |
|
426 |
- movie->pkt0 = movie->pkt = pkt; |
|
427 |
- break; |
|
428 |
- } |
|
429 |
- } |
|
430 |
- |
|
431 |
- if (ret == AVERROR_EOF) { |
|
432 |
- movie->state = STATE_DONE; |
|
433 |
- return ret; |
|
434 |
- } |
|
435 |
- } |
|
436 |
- |
|
437 |
- /* decode and update the movie pkt */ |
|
438 |
- avcodec_get_frame_defaults(movie->frame); |
|
439 |
- ret = avcodec_decode_audio4(movie->codec_ctx, movie->frame, &got_frame, &movie->pkt); |
|
440 |
- if (ret < 0) { |
|
441 |
- movie->pkt.size = 0; |
|
442 |
- return ret; |
|
443 |
- } |
|
444 |
- movie->pkt.data += ret; |
|
445 |
- movie->pkt.size -= ret; |
|
446 |
- |
|
447 |
- /* wrap the decoded data in a samplesref */ |
|
448 |
- if (got_frame) { |
|
449 |
- int nb_samples = movie->frame->nb_samples; |
|
450 |
- int data_size = |
|
451 |
- av_samples_get_buffer_size(NULL, movie->codec_ctx->channels, |
|
452 |
- nb_samples, movie->codec_ctx->sample_fmt, 1); |
|
453 |
- if (data_size < 0) |
|
454 |
- return data_size; |
|
455 |
- movie->samplesref = |
|
456 |
- ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); |
|
457 |
- memcpy(movie->samplesref->data[0], movie->frame->data[0], data_size); |
|
458 |
- movie->samplesref->pts = movie->pkt.pts; |
|
459 |
- movie->samplesref->pos = movie->pkt.pos; |
|
460 |
- movie->samplesref->audio->sample_rate = movie->codec_ctx->sample_rate; |
|
461 |
- } |
|
462 |
- |
|
463 |
- // We got it. Free the packet since we are returning |
|
464 |
- if (movie->pkt.size <= 0) |
|
465 |
- av_free_packet(&movie->pkt0); |
|
466 |
- |
|
467 |
- return 0; |
|
468 |
-} |
|
469 |
- |
|
470 |
-static int amovie_request_frame(AVFilterLink *outlink) |
|
471 |
-{ |
|
472 |
- MovieContext *movie = outlink->src->priv; |
|
473 |
- int ret; |
|
474 |
- |
|
475 |
- if (movie->state == STATE_DONE) |
|
476 |
- return AVERROR_EOF; |
|
477 |
- do { |
|
478 |
- if ((ret = amovie_get_samples(outlink)) < 0) |
|
479 |
- return ret; |
|
480 |
- } while (!movie->samplesref); |
|
481 |
- |
|
482 |
- ff_filter_samples(outlink, avfilter_ref_buffer(movie->samplesref, ~0)); |
|
483 |
- avfilter_unref_buffer(movie->samplesref); |
|
484 |
- movie->samplesref = NULL; |
|
485 |
- |
|
486 |
- return 0; |
|
487 |
-} |
|
488 |
- |
|
489 | 493 |
AVFilter avfilter_asrc_amovie = { |
490 | 494 |
.name = "amovie", |
491 | 495 |
.description = NULL_IF_CONFIG_SMALL("Read audio from a movie source."), |
492 | 496 |
.priv_size = sizeof(MovieContext), |
493 |
- .init = amovie_init, |
|
494 |
- .uninit = movie_common_uninit, |
|
495 |
- .query_formats = amovie_query_formats, |
|
497 |
+ .init = movie_init, |
|
498 |
+ .uninit = movie_uninit, |
|
499 |
+ .query_formats = movie_query_formats, |
|
496 | 500 |
|
497 | 501 |
.inputs = (const AVFilterPad[]) {{ .name = NULL }}, |
498 |
- .outputs = (const AVFilterPad[]) {{ .name = "default", |
|
499 |
- .type = AVMEDIA_TYPE_AUDIO, |
|
500 |
- .request_frame = amovie_request_frame, |
|
501 |
- .config_props = amovie_config_output_props, }, |
|
502 |
- { .name = NULL}}, |
|
502 |
+ .outputs = (const AVFilterPad[]) {{ .name = NULL }}, |
|
503 | 503 |
}; |
504 | 504 |
|
505 | 505 |
#endif /* CONFIG_AMOVIE_FILTER */ |