Le quintidi 15 messidor, an CCXXIII, Stephan Holljes a écrit : > Signed-off-by: Stephan Holljes <klaxa1...@googlemail.com> > --- > doc/examples/Makefile | 1 + > doc/examples/http_multiclient.c | 101 > ++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 102 insertions(+) > create mode 100644 doc/examples/http_multiclient.c > > diff --git a/doc/examples/Makefile b/doc/examples/Makefile > index 9699f11..8c9501b 100644 > --- a/doc/examples/Makefile > +++ b/doc/examples/Makefile > @@ -18,6 +18,7 @@ EXAMPLES= avio_list_dir \ > extract_mvs \ > filtering_video \ > filtering_audio \ > + http_multiclient \ > metadata \ > muxing \ > remuxing \ > diff --git a/doc/examples/http_multiclient.c b/doc/examples/http_multiclient.c > new file mode 100644 > index 0000000..fdecab4 > --- /dev/null > +++ b/doc/examples/http_multiclient.c > @@ -0,0 +1,101 @@ > +/* > + * copyright (c) 2015 Stephan Holljes > + * > + * 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 > + */ > + > +/** > + * @file > + * libavformat multi-client network API usage example. > + * > + * @example http_multiclient.c > + * This example will serve a file without decoding or demuxing it over http.
> + * Multiple clients can connect and will receive the same file. Did you test several simultaneous clients? It should work, because fork() is a strong isolation, so it if works for one it works for many, but testing is always better. > + */ > + > +#include <libavformat/avformat.h> > +#include <unistd.h> > + > +int main(int argc, char **argv) > +{ > + AVDictionary *options = NULL; > + AVIOContext *input = NULL, *client = NULL, *server = NULL; > + const char *in_uri, *out_uri; > + int ret, pid, n; > + uint8_t buf[1024]; > + > + if (argc < 3) { > + printf("usage: %s input http://hostname[:port]\n" > + "API example program to serve http to multiple clients.\n" > + "The output format is guessed according to the input file > extension.\n" I suspect this sentence is outdated. > + "\n", argv[0]); > + return 1; > + } > + > + in_uri = argv[1]; > + out_uri = argv[2]; > + > + av_register_all(); > + avformat_network_init(); > + > + if ((ret = av_dict_set(&options, "listen", "2", 0)) < 0) > + goto end; > + if ((ret = avio_open2(&server, out_uri, AVIO_FLAG_READ_WRITE, NULL, > &options)) < 0) > + goto end; > + fprintf(stderr, "Entering main loop.\n"); > + for(;;) { > + if ((ret = avio_accept(server, &client)) < 0) > + goto end; > + fprintf(stderr, "Accepted client, forking process.\n"); > + pid = fork(); Zombie apocalypse ahead! Well, setting SIGCHLD to SIG_IGN is hardly portable, double-fork is ugly and proper waiting is painful, so I guess we can leave the zombies for now in a simple testing program, but a comment stating it would be useful. > + if (pid == 0) { Maybe also: if (pid < 0) { perror("Fork failed"); err = AVERROR(errno); goto end; } > + fprintf(stderr, "Opening input file.\n"); > + if ((ret = avio_open2(&input, in_uri, AVIO_FLAG_READ, NULL, > NULL)) < 0) > + goto end; > + fprintf(stderr, "In child.\n"); > + avio_handshake(client); > + fprintf(stderr, "Handshake performed.\n"); It would feel more natural to perform the handshake before opening the input file. Note that since this is your code, you are free to reject this kind of stylistic remark. In this particular case, it will be necessary when extending the code, because avio_handshake() will be responsible for getting the request file name from the client. Also: since this is fork()ing instead of pthread_create()ing, you probably should close the server context in the client process. And you definitely must close the client context in the server process. > + for(;;) { > + n = avio_read(input, buf, sizeof(buf)); > + fprintf(stderr, "Read %d bytes from input.\n", n); > + if (n <= 0) { > + fprintf(stderr, "n is negative, abort.\n"); > + break; > + } n == 0 is not possible and not supposed to be possible according to the API. n < 0 is a proper error code, but the particular code AVERROR_EOF should not be treated as an error, i.e. not print an alarming error message. It usually goes something like that: if (n < 0) { if (n == AVERROR_EOF) break; av_log(ctx, AV_LOG_ERROR, "Error reading from input: %s\n", av_err2str(n)); goto fail; } > + fprintf(stderr, "Writing %d bytes of data.\n", n); > + avio_write(client, buf, n); > + avio_flush(client); > + } > + fprintf(stderr, "Flushing client\n"); > + avio_flush(client); > + fprintf(stderr, "Closing client\n"); > + avio_close(client); > + break; > + } > + } > + > +end: > + if (ret) > + fprintf(stderr, "Some errors occured.\n"); av_err2str() to know what exactly. And knowing where the error happened would be nicer. > + if (server) > + avio_close(server); > + if (input) > + avio_close(input); No need to check, avio_close() works for NULL. > + if (ret < 0 && ret != AVERROR_EOF) > + return 1; > + return 0; > +} Regards, -- Nicolas George
signature.asc
Description: Digital signature
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel