Re: [FFmpeg-devel] [PATCH] libavformat: add "capture:" protocol using AVIO
On Tue, Apr 11, 2017 at 14:12:08 +1000, Timothy Lee wrote: > Capture is an input stream capture protocol that dumps the input stream to a > file. The default name of the output file is "capture.dat", but it can be > changed using the "capture_file" option. Nice! > +Input stream capturing protocol. Probably worth pointing out more exactly what it does. Even I can only guess: Dumps the raw payload, in *addition* to demuxing the input as normal. > +A capture URL has the form: > +@example > +capture:@var{URL} That makes it an additional protocol prefix, right? So you can end up having two (or more?). "capture:file:/path/bla" (Confusing to me as a user at first sight, but ingenious if it works. Yes, I did test it.) > +For example, to capture the input stream as @file{stream.sav} during > playback: > +@example > +ffplay -capture_file stream.sav capture:@var{URL} So, is this the perfect replacement for "mplayer -dumpstream [-dumpfile capture.dat]"? :-) Probably also worth noting somewhere. If you go with Nicolas's suggestions, this comment is obsolete, but: > +c->fd = avpriv_open(c->capture_file, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, > 0666); > +if (c->fd < 0) > +av_log(h, AV_LOG_ERROR, "Failed to create capture file\n"); If you're going to print a message, please also evaluate errno, for the sake of the user. Moritz ___ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
Re: [FFmpeg-devel] [PATCH] libavformat: add "capture:" protocol using AVIO
Le duodi 22 germinal, an CCXXV, Timothy Lee a écrit : > Capture is an input stream capture protocol that dumps the input stream to a > file. The default name of the output file is "capture.dat", but it can be > changed using the "capture_file" option. > --- > Changelog | 1 + > doc/protocols.texi | 23 ++ > libavformat/Makefile| 1 + > libavformat/capture.c | 112 > > libavformat/protocols.c | 1 + > 5 files changed, 138 insertions(+) > create mode 100644 libavformat/capture.c Thanks, I like this version much better. See comments below. > > diff --git a/Changelog b/Changelog > index e76b324f61..3c06e84185 100644 > --- a/Changelog > +++ b/Changelog > @@ -36,6 +36,7 @@ version 3.3: > - MPEG-7 Video Signature filter > - Removed asyncts filter (use af_aresample instead) > - Intel QSV-accelerated VP8 video decoding > +- capture protocol > > > version 3.2: > diff --git a/doc/protocols.texi b/doc/protocols.texi > index a7968ff56e..89a1f2afa8 100644 > --- a/doc/protocols.texi > +++ b/doc/protocols.texi > @@ -103,6 +103,29 @@ Cache the input stream to temporary file. It brings > seeking capability to live s > cache:@var{URL} > @end example > > +@section capture > + > +Input stream capturing protocol. > + > +A capture URL has the form: > +@example > +capture:@var{URL} > +@end example > + > +This protocol accepts the following option: > +@table @option > + > +@item capture_file > +Name of the capture file. > +If not specified, the input stream will be written into @file{capture.dat}. > + > +@end table > + > +For example, to capture the input stream as @file{stream.sav} during > playback: > +@example > +ffplay -capture_file stream.sav capture:@var{URL} > +@end example > + > @section concat > > Physical concatenation protocol. > diff --git a/libavformat/Makefile b/libavformat/Makefile > index a1dae894fe..08d23baf95 100644 > --- a/libavformat/Makefile > +++ b/libavformat/Makefile > @@ -549,6 +549,7 @@ OBJS-$(CONFIG_ASYNC_PROTOCOL)+= async.o > OBJS-$(CONFIG_APPLEHTTP_PROTOCOL)+= hlsproto.o > OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o > OBJS-$(CONFIG_CACHE_PROTOCOL)+= cache.o > +OBJS-$(CONFIG_CAPTURE_PROTOCOL) += capture.o > OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o > OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o > OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o > diff --git a/libavformat/capture.c b/libavformat/capture.c > new file mode 100644 > index 00..90daf40877 > --- /dev/null > +++ b/libavformat/capture.c > @@ -0,0 +1,112 @@ > +/* > + * Input capture protocol. > + * Copyright (c) 2017 Timothy Lee > + * > + * This file is part of FFmpeg. > + * > + * FFmpeg 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. > + * > + * FFmpeg 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 FFmpeg; if not, write to the Free Software > + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 > USA > + */ > + > +#include "libavutil/avstring.h" > +#include "libavutil/opt.h" > +#include "avformat.h" > +#include "avio.h" > +#include > +#if HAVE_IO_H > +#include > +#endif > +#if HAVE_UNISTD_H > +#include > +#endif > +#include > +#include > +#include "os_support.h" > +#include "url.h" > + > +#ifndef O_BINARY > +# define O_BINARY 0 > +#endif Is there a reason you use direct I/O, and have to suffer all that boilerplate code? You could achieve the same result with avio_open2(&c->capture, c->capture_file), with extra features and less code. > + > +typedef struct Context { > +AVClass *class; > +int fd; > +int64_t count; > +AVIOContext *io; > +const char *capture_file; > +} Context; > + > +static int capture_open(URLContext *h, const char *arg, int flags, > AVDictionary **options) > +{ > +Context *c= h->priv_data; > +c->fd = avpriv_open(c->capture_file, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, > 0666); > +if (c->fd < 0) > +av_log(h, AV_LOG_ERROR, "Failed to create capture file\n"); I think it would be better to return an error than test fd everywhere. > +av_strstart(arg, "capture:", &arg); > +return avio_open2(&c->io, arg, flags, &h->interrupt_callback, options); > +} > + > +static int capture_read(URLContext *h, unsigned char *buf, int size) > +{ > +Context *c = h->priv_data; > +int r = avio_read(c->io, buf, size); > +if ((r > 0) && (c->fd >= 0)) > +{ Nit: br
[FFmpeg-devel] [PATCH] libavformat: add "capture:" protocol using AVIO
Capture is an input stream capture protocol that dumps the input stream to a file. The default name of the output file is "capture.dat", but it can be changed using the "capture_file" option. --- Changelog | 1 + doc/protocols.texi | 23 ++ libavformat/Makefile| 1 + libavformat/capture.c | 112 libavformat/protocols.c | 1 + 5 files changed, 138 insertions(+) create mode 100644 libavformat/capture.c diff --git a/Changelog b/Changelog index e76b324f61..3c06e84185 100644 --- a/Changelog +++ b/Changelog @@ -36,6 +36,7 @@ version 3.3: - MPEG-7 Video Signature filter - Removed asyncts filter (use af_aresample instead) - Intel QSV-accelerated VP8 video decoding +- capture protocol version 3.2: diff --git a/doc/protocols.texi b/doc/protocols.texi index a7968ff56e..89a1f2afa8 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -103,6 +103,29 @@ Cache the input stream to temporary file. It brings seeking capability to live s cache:@var{URL} @end example +@section capture + +Input stream capturing protocol. + +A capture URL has the form: +@example +capture:@var{URL} +@end example + +This protocol accepts the following option: +@table @option + +@item capture_file +Name of the capture file. +If not specified, the input stream will be written into @file{capture.dat}. + +@end table + +For example, to capture the input stream as @file{stream.sav} during playback: +@example +ffplay -capture_file stream.sav capture:@var{URL} +@end example + @section concat Physical concatenation protocol. diff --git a/libavformat/Makefile b/libavformat/Makefile index a1dae894fe..08d23baf95 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -549,6 +549,7 @@ OBJS-$(CONFIG_ASYNC_PROTOCOL)+= async.o OBJS-$(CONFIG_APPLEHTTP_PROTOCOL)+= hlsproto.o OBJS-$(CONFIG_BLURAY_PROTOCOL) += bluray.o OBJS-$(CONFIG_CACHE_PROTOCOL)+= cache.o +OBJS-$(CONFIG_CAPTURE_PROTOCOL) += capture.o OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o diff --git a/libavformat/capture.c b/libavformat/capture.c new file mode 100644 index 00..90daf40877 --- /dev/null +++ b/libavformat/capture.c @@ -0,0 +1,112 @@ +/* + * Input capture protocol. + * Copyright (c) 2017 Timothy Lee + * + * This file is part of FFmpeg. + * + * FFmpeg 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. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/opt.h" +#include "avformat.h" +#include "avio.h" +#include +#if HAVE_IO_H +#include +#endif +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include "os_support.h" +#include "url.h" + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +typedef struct Context { +AVClass *class; +int fd; +int64_t count; +AVIOContext *io; +const char *capture_file; +} Context; + +static int capture_open(URLContext *h, const char *arg, int flags, AVDictionary **options) +{ +Context *c= h->priv_data; +c->fd = avpriv_open(c->capture_file, O_WRONLY|O_BINARY|O_TRUNC|O_CREAT, 0666); +if (c->fd < 0) +av_log(h, AV_LOG_ERROR, "Failed to create capture file\n"); +av_strstart(arg, "capture:", &arg); +return avio_open2(&c->io, arg, flags, &h->interrupt_callback, options); +} + +static int capture_read(URLContext *h, unsigned char *buf, int size) +{ +Context *c = h->priv_data; +int r = avio_read(c->io, buf, size); +if ((r > 0) && (c->fd >= 0)) +{ +if (write(c->fd, buf, r) == r) +c->count += r; +else +av_log(h, AV_LOG_ERROR, "Cannot write to capture file\n"); +} +return r; +} + +static int64_t capture_seek(URLContext *h, int64_t pos, int whence) +{ +Context *c = h->priv_data; +return avio_seek(c->io, pos, whence); +} + +static int capture_close(URLContext *h) +{ +Context *c = h->priv_data; +av_log(h, AV_LOG_INFO, "Captured %"PRId64" bytes\n", c->count); +if (c->fd >= 0) +close(c->fd); +return avio_closep(&c->io); +} + +#define OFFSET(x) offsetof(Context, x) +#define D AV_OPT_FLAG_DECODING_PARAM + +static const AVOption options[] = { +{ "capture_file",