| 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 | |
| 27 | static int usage(const char *argv0, int ret) |
| 28 | { |
| 29 | fprintf(stderr, "%s [-b bytespersec] [-d duration] input_url output_url\n", argv0); |
| 30 | return ret; |
| 31 | } |
| 32 | |
| 33 | int main(int argc, char **argv) |
| 34 | { |
| 35 | int bps = 0, duration = 0, ret, i; |
| 36 | const char *input_url = NULL, *output_url = NULL; |
| 37 | int64_t stream_pos = 0; |
| 38 | int64_t start_time; |
| 39 | char errbuf[50]; |
| 40 | AVIOContext *input, *output; |
| 41 | |
| 42 | av_register_all(); |
| 43 | avformat_network_init(); |
| 44 | |
| 45 | for (i = 1; i < argc; i++) { |
| 46 | if (!strcmp(argv[i], "-b") && i + 1 < argc) { |
| 47 | bps = atoi(argv[i + 1]); |
| 48 | i++; |
| 49 | } else if (!strcmp(argv[i], "-d") && i + 1 < argc) { |
| 50 | duration = atoi(argv[i + 1]); |
| 51 | i++; |
| 52 | } else if (!input_url) { |
| 53 | input_url = argv[i]; |
| 54 | } else if (!output_url) { |
| 55 | output_url = argv[i]; |
| 56 | } else { |
| 57 | return usage(argv[0], 1); |
| 58 | } |
| 59 | } |
| 60 | if (!output_url) |
| 61 | return usage(argv[0], 1); |
| 62 | |
| 63 | ret = avio_open2(&input, input_url, AVIO_FLAG_READ, NULL, NULL); |
| 64 | if (ret) { |
| 65 | av_strerror(ret, errbuf, sizeof(errbuf)); |
| 66 | fprintf(stderr, "Unable to open %s: %s\n", input_url, errbuf); |
| 67 | return 1; |
| 68 | } |
| 69 | if (duration && !bps) { |
| 70 | int64_t size = avio_size(input); |
| 71 | if (size < 0) { |
| 72 | av_strerror(ret, errbuf, sizeof(errbuf)); |
| 73 | fprintf(stderr, "Unable to get size of %s: %s\n", input_url, errbuf); |
| 74 | goto fail; |
| 75 | } |
| 76 | bps = size / duration; |
| 77 | } |
| 78 | ret = avio_open2(&output, output_url, AVIO_FLAG_WRITE, NULL, NULL); |
| 79 | if (ret) { |
| 80 | av_strerror(ret, errbuf, sizeof(errbuf)); |
| 81 | fprintf(stderr, "Unable to open %s: %s\n", output_url, errbuf); |
| 82 | goto fail; |
| 83 | } |
| 84 | |
| 85 | start_time = av_gettime_relative(); |
| 86 | while (1) { |
| 87 | uint8_t buf[1024]; |
| 88 | int n; |
| 89 | n = avio_read(input, buf, sizeof(buf)); |
| 90 | if (n <= 0) |
| 91 | break; |
| 92 | avio_write(output, buf, n); |
| 93 | stream_pos += n; |
| 94 | if (bps) { |
| 95 | avio_flush(output); |
| 96 | while ((av_gettime_relative() - start_time) * bps / AV_TIME_BASE < stream_pos) |
| 97 | av_usleep(50 * 1000); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | avio_flush(output); |
| 102 | avio_close(output); |
| 103 | |
| 104 | fail: |
| 105 | avio_close(input); |
| 106 | avformat_network_deinit(); |
| 107 | return ret ? 1 : 0; |
| 108 | } |