1/* 2 * Copyright (c) 2012 Martin Storsjo 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23 24#include "libavutil/time.h" 25#include "libavformat/avformat.h" 26 27static int usage(const char *argv0, int ret) 28{ 29 fprintf(stderr, "%s [-b bytespersec] [-d duration] [-oi <options>] [-oo <options>] [-v] input_url output_url\n", argv0); 30 fprintf(stderr, "<options>: AVOptions expressed as key=value, :-separated\n"); 31 return ret; 32} 33 34int main(int argc, char **argv) 35{ 36 int bps = 0, duration = 0, verbose = 0, ret, i; 37 const char *input_url = NULL, *output_url = NULL; 38 int64_t stream_pos = 0; 39 int64_t start_time; 40 char errbuf[50]; 41 AVIOContext *input, *output; 42 AVDictionary *in_opts = NULL; 43 AVDictionary *out_opts = NULL; 44 45 avformat_network_init(); 46 47 for (i = 1; i < argc; i++) { 48 if (!strcmp(argv[i], "-b") && i + 1 < argc) { 49 bps = atoi(argv[i + 1]); 50 i++; 51 } else if (!strcmp(argv[i], "-d") && i + 1 < argc) { 52 duration = atoi(argv[i + 1]); 53 i++; 54 } else if (!strcmp(argv[i], "-oi") && i + 1 < argc) { 55 if (av_dict_parse_string(&in_opts, argv[i + 1], "=", ":", 0) < 0) { 56 fprintf(stderr, "Cannot parse option string %s\n", 57 argv[i + 1]); 58 return usage(argv[0], 1); 59 } 60 i++; 61 } else if (!strcmp(argv[i], "-oo") && i + 1 < argc) { 62 if (av_dict_parse_string(&out_opts, argv[i + 1], "=", ":", 0) < 0) { 63 fprintf(stderr, "Cannot parse option string %s\n", 64 argv[i + 1]); 65 return usage(argv[0], 1); 66 } 67 i++; 68 } else if (!strcmp(argv[i], "-v")) { 69 verbose = 1; 70 } else if (!input_url) { 71 input_url = argv[i]; 72 } else if (!output_url) { 73 output_url = argv[i]; 74 } else { 75 return usage(argv[0], 1); 76 } 77 } 78 if (!output_url) 79 return usage(argv[0], 1); 80 81 ret = avio_open2(&input, input_url, AVIO_FLAG_READ, NULL, &in_opts); 82 if (ret) { 83 av_strerror(ret, errbuf, sizeof(errbuf)); 84 fprintf(stderr, "Unable to open %s: %s\n", input_url, errbuf); 85 return 1; 86 } 87 if (verbose) { 88 int64_t size = avio_seek(input, 0, AVSEEK_SIZE); 89 if (size >= 0) { 90 fprintf(stderr, "aviocat: input size: %"PRId64"\n", size); 91 } else { 92 fprintf(stderr, "aviocat: input size: unknown\n"); 93 } 94 } 95 if (duration && !bps) { 96 int64_t size = avio_size(input); 97 if (size < 0) { 98 av_strerror(ret, errbuf, sizeof(errbuf)); 99 fprintf(stderr, "Unable to get size of %s: %s\n", input_url, errbuf); 100 goto fail; 101 } 102 bps = size / duration; 103 } 104 ret = avio_open2(&output, output_url, AVIO_FLAG_WRITE, NULL, &out_opts); 105 if (ret) { 106 av_strerror(ret, errbuf, sizeof(errbuf)); 107 fprintf(stderr, "Unable to open %s: %s\n", output_url, errbuf); 108 goto fail; 109 } 110 111 start_time = av_gettime_relative(); 112 while (1) { 113 uint8_t buf[1024]; 114 int n; 115 n = avio_read(input, buf, sizeof(buf)); 116 if (n <= 0) 117 break; 118 avio_write(output, buf, n); 119 if (output->error) { 120 av_strerror(output->error, errbuf, sizeof(errbuf)); 121 fprintf(stderr, "Unable to write %s: %s\n", output_url, errbuf); 122 break; 123 } 124 stream_pos += n; 125 if (bps) { 126 avio_flush(output); 127 while ((av_gettime_relative() - start_time) * bps / AV_TIME_BASE < stream_pos) 128 av_usleep(50 * 1000); 129 } 130 } 131 132 avio_flush(output); 133 avio_close(output); 134 135fail: 136 av_dict_free(&in_opts); 137 av_dict_free(&out_opts); 138 avio_close(input); 139 avformat_network_deinit(); 140 return ret ? 1 : 0; 141} 142