| OLD | NEW |
| 1 /* | 1 /* |
| 2 * RTMP network protocol | 2 * RTMP network protocol |
| 3 * Copyright (c) 2009 Kostya Shishkov | 3 * Copyright (c) 2009 Kostya Shishkov |
| 4 * | 4 * |
| 5 * This file is part of FFmpeg. | 5 * This file is part of FFmpeg. |
| 6 * | 6 * |
| 7 * FFmpeg is free software; you can redistribute it and/or | 7 * FFmpeg is free software; you can redistribute it and/or |
| 8 * modify it under the terms of the GNU Lesser General Public | 8 * modify it under the terms of the GNU Lesser General Public |
| 9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
| 10 * version 2.1 of the License, or (at your option) any later version. | 10 * version 2.1 of the License, or (at your option) any later version. |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 int chunk_size; ///< size of the chunks RTMP packe
ts are divided into | 65 int chunk_size; ///< size of the chunks RTMP packe
ts are divided into |
| 66 int is_input; ///< input/output flag | 66 int is_input; ///< input/output flag |
| 67 char playpath[256]; ///< path to filename to play (wit
h possible "mp4:" prefix) | 67 char playpath[256]; ///< path to filename to play (wit
h possible "mp4:" prefix) |
| 68 char app[128]; ///< application | 68 char app[128]; ///< application |
| 69 ClientState state; ///< current state | 69 ClientState state; ///< current state |
| 70 int main_channel_id; ///< an additional channel ID whic
h is used for some invocations | 70 int main_channel_id; ///< an additional channel ID whic
h is used for some invocations |
| 71 uint8_t* flv_data; ///< buffer with data for demuxer | 71 uint8_t* flv_data; ///< buffer with data for demuxer |
| 72 int flv_size; ///< current buffer size | 72 int flv_size; ///< current buffer size |
| 73 int flv_off; ///< number of bytes read from cur
rent buffer | 73 int flv_off; ///< number of bytes read from cur
rent buffer |
| 74 RTMPPacket out_pkt; ///< rtmp packet, created from flv
a/v or metadata (for output) | 74 RTMPPacket out_pkt; ///< rtmp packet, created from flv
a/v or metadata (for output) |
| 75 uint32_t client_report_size; ///< number of bytes after which c
lient should report to server |
| 76 uint32_t bytes_read; ///< number of bytes read from ser
ver |
| 77 uint32_t last_bytes_read; ///< number of bytes read last rep
orted to server |
| 75 } RTMPContext; | 78 } RTMPContext; |
| 76 | 79 |
| 77 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first
client digest signing | 80 #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first
client digest signing |
| 78 /** Client key used for digest signing */ | 81 /** Client key used for digest signing */ |
| 79 static const uint8_t rtmp_player_key[] = { | 82 static const uint8_t rtmp_player_key[] = { |
| 80 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', | 83 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', |
| 81 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '
1', | 84 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '
1', |
| 82 | 85 |
| 83 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02
, | 86 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02
, |
| 84 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8
, | 87 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8
, |
| (...skipping 18 matching lines...) Expand all Loading... |
| 103 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto, | 106 static void gen_connect(URLContext *s, RTMPContext *rt, const char *proto, |
| 104 const char *host, int port) | 107 const char *host, int port) |
| 105 { | 108 { |
| 106 RTMPPacket pkt; | 109 RTMPPacket pkt; |
| 107 uint8_t ver[64], *p; | 110 uint8_t ver[64], *p; |
| 108 char tcurl[512]; | 111 char tcurl[512]; |
| 109 | 112 |
| 110 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096); | 113 ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE, 0, 4096); |
| 111 p = pkt.data; | 114 p = pkt.data; |
| 112 | 115 |
| 113 snprintf(tcurl, sizeof(tcurl), "%s://%s:%d/%s", proto, host, port, rt->app); | 116 ff_url_join(tcurl, sizeof(tcurl), proto, NULL, host, port, "/%s", rt->app); |
| 114 ff_amf_write_string(&p, "connect"); | 117 ff_amf_write_string(&p, "connect"); |
| 115 ff_amf_write_number(&p, 1.0); | 118 ff_amf_write_number(&p, 1.0); |
| 116 ff_amf_write_object_start(&p); | 119 ff_amf_write_object_start(&p); |
| 117 ff_amf_write_field_name(&p, "app"); | 120 ff_amf_write_field_name(&p, "app"); |
| 118 ff_amf_write_string(&p, rt->app); | 121 ff_amf_write_string(&p, rt->app); |
| 119 | 122 |
| 120 if (rt->is_input) { | 123 if (rt->is_input) { |
| 121 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_
CLIENT_VER1, | 124 snprintf(ver, sizeof(ver), "%s %d,%d,%d,%d", RTMP_CLIENT_PLATFORM, RTMP_
CLIENT_VER1, |
| 122 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4); | 125 RTMP_CLIENT_VER2, RTMP_CLIENT_VER3, RTMP_CLIENT_VER4); |
| 123 } else { | 126 } else { |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 uint8_t *p; | 333 uint8_t *p; |
| 331 | 334 |
| 332 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timest
amp + 1, 6); | 335 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING, ppkt->timest
amp + 1, 6); |
| 333 p = pkt.data; | 336 p = pkt.data; |
| 334 bytestream_put_be16(&p, 7); | 337 bytestream_put_be16(&p, 7); |
| 335 bytestream_put_be32(&p, AV_RB32(ppkt->data+2)); | 338 bytestream_put_be32(&p, AV_RB32(ppkt->data+2)); |
| 336 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); | 339 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
| 337 ff_rtmp_packet_destroy(&pkt); | 340 ff_rtmp_packet_destroy(&pkt); |
| 338 } | 341 } |
| 339 | 342 |
| 343 /** |
| 344 * Generates report on bytes read so far and sends it to the server. |
| 345 */ |
| 346 static void gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts) |
| 347 { |
| 348 RTMPPacket pkt; |
| 349 uint8_t *p; |
| 350 |
| 351 ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ, ts, 4)
; |
| 352 p = pkt.data; |
| 353 bytestream_put_be32(&p, rt->bytes_read); |
| 354 ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size, rt->prev_pkt[1]); |
| 355 ff_rtmp_packet_destroy(&pkt); |
| 356 } |
| 357 |
| 340 //TODO: Move HMAC code somewhere. Eventually. | 358 //TODO: Move HMAC code somewhere. Eventually. |
| 341 #define HMAC_IPAD_VAL 0x36 | 359 #define HMAC_IPAD_VAL 0x36 |
| 342 #define HMAC_OPAD_VAL 0x5C | 360 #define HMAC_OPAD_VAL 0x5C |
| 343 | 361 |
| 344 /** | 362 /** |
| 345 * Calculates HMAC-SHA2 digest for RTMP handshake packets. | 363 * Calculates HMAC-SHA2 digest for RTMP handshake packets. |
| 346 * | 364 * |
| 347 * @param src input buffer | 365 * @param src input buffer |
| 348 * @param len input buffer length (should be 1536) | 366 * @param len input buffer length (should be 1536) |
| 349 * @param gap offset in buffer where 32 bytes should not be taken into accoun
t | 367 * @param gap offset in buffer where 32 bytes should not be taken into accoun
t |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->c
hunk_size); | 567 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->c
hunk_size); |
| 550 return -1; | 568 return -1; |
| 551 } | 569 } |
| 552 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_siz
e); | 570 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_siz
e); |
| 553 break; | 571 break; |
| 554 case RTMP_PT_PING: | 572 case RTMP_PT_PING: |
| 555 t = AV_RB16(pkt->data); | 573 t = AV_RB16(pkt->data); |
| 556 if (t == 6) | 574 if (t == 6) |
| 557 gen_pong(s, rt, pkt); | 575 gen_pong(s, rt, pkt); |
| 558 break; | 576 break; |
| 577 case RTMP_PT_CLIENT_BW: |
| 578 if (pkt->data_size < 4) { |
| 579 av_log(LOG_CONTEXT, AV_LOG_ERROR, |
| 580 "Client bandwidth report packet is less than 4 bytes long (%d
)\n", |
| 581 pkt->data_size); |
| 582 return -1; |
| 583 } |
| 584 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt
->data)); |
| 585 rt->client_report_size = AV_RB32(pkt->data) >> 1; |
| 586 break; |
| 559 case RTMP_PT_INVOKE: | 587 case RTMP_PT_INVOKE: |
| 560 //TODO: check for the messages sent for wrong state? | 588 //TODO: check for the messages sent for wrong state? |
| 561 if (!memcmp(pkt->data, "\002\000\006_error", 9)) { | 589 if (!memcmp(pkt->data, "\002\000\006_error", 9)) { |
| 562 uint8_t tmpstr[256]; | 590 uint8_t tmpstr[256]; |
| 563 | 591 |
| 564 if (!ff_amf_get_field_value(pkt->data + 9, data_end, | 592 if (!ff_amf_get_field_value(pkt->data + 9, data_end, |
| 565 "description", tmpstr, sizeof(tmpstr))) | 593 "description", tmpstr, sizeof(tmpstr))) |
| 566 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr); | 594 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Server error: %s\n",tmpstr); |
| 567 return -1; | 595 return -1; |
| 568 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) { | 596 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 for (;;) { | 690 for (;;) { |
| 663 RTMPPacket rpkt; | 691 RTMPPacket rpkt; |
| 664 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt, | 692 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt, |
| 665 rt->chunk_size, rt->prev_pkt[0])) <= 0) { | 693 rt->chunk_size, rt->prev_pkt[0])) <= 0) { |
| 666 if (ret == 0) { | 694 if (ret == 0) { |
| 667 return AVERROR(EAGAIN); | 695 return AVERROR(EAGAIN); |
| 668 } else { | 696 } else { |
| 669 return AVERROR(EIO); | 697 return AVERROR(EIO); |
| 670 } | 698 } |
| 671 } | 699 } |
| 700 rt->bytes_read += ret; |
| 701 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) { |
| 702 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Sending bytes read report\n"); |
| 703 gen_bytes_read(s, rt, rpkt.timestamp + 1); |
| 704 rt->last_bytes_read = rt->bytes_read; |
| 705 } |
| 672 | 706 |
| 673 ret = rtmp_parse_result(s, rt, &rpkt); | 707 ret = rtmp_parse_result(s, rt, &rpkt); |
| 674 if (ret < 0) {//serious error in current packet | 708 if (ret < 0) {//serious error in current packet |
| 675 ff_rtmp_packet_destroy(&rpkt); | 709 ff_rtmp_packet_destroy(&rpkt); |
| 676 return -1; | 710 return -1; |
| 677 } | 711 } |
| 678 if (rt->state == STATE_STOPPED) { | 712 if (rt->state == STATE_STOPPED) { |
| 679 ff_rtmp_packet_destroy(&rpkt); | 713 ff_rtmp_packet_destroy(&rpkt); |
| 680 return AVERROR_EOF; | 714 return AVERROR_EOF; |
| 681 } | 715 } |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 771 uint8_t buf[2048]; | 805 uint8_t buf[2048]; |
| 772 int port; | 806 int port; |
| 773 int ret; | 807 int ret; |
| 774 | 808 |
| 775 rt = av_mallocz(sizeof(RTMPContext)); | 809 rt = av_mallocz(sizeof(RTMPContext)); |
| 776 if (!rt) | 810 if (!rt) |
| 777 return AVERROR(ENOMEM); | 811 return AVERROR(ENOMEM); |
| 778 s->priv_data = rt; | 812 s->priv_data = rt; |
| 779 rt->is_input = !(flags & URL_WRONLY); | 813 rt->is_input = !(flags & URL_WRONLY); |
| 780 | 814 |
| 781 url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, | 815 ff_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &por
t, |
| 782 path, sizeof(path), s->filename); | 816 path, sizeof(path), s->filename); |
| 783 | 817 |
| 784 if (port < 0) | 818 if (port < 0) |
| 785 port = RTMP_DEFAULT_PORT; | 819 port = RTMP_DEFAULT_PORT; |
| 786 snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port); | 820 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL); |
| 787 | 821 |
| 788 if (url_open(&rt->stream, buf, URL_RDWR) < 0) { | 822 if (url_open(&rt->stream, buf, URL_RDWR) < 0) { |
| 789 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot open connection %s\n", buf); | 823 av_log(LOG_CONTEXT, AV_LOG_ERROR, "Cannot open connection %s\n", buf); |
| 790 goto fail; | 824 goto fail; |
| 791 } | 825 } |
| 792 | 826 |
| 793 rt->state = STATE_START; | 827 rt->state = STATE_START; |
| 794 if (rtmp_handshake(s, rt)) | 828 if (rtmp_handshake(s, rt)) |
| 795 return -1; | 829 return -1; |
| 796 | 830 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 819 } | 853 } |
| 820 if (!strchr(fname, ':') && | 854 if (!strchr(fname, ':') && |
| 821 (!strcmp(fname + strlen(fname) - 4, ".f4v") || | 855 (!strcmp(fname + strlen(fname) - 4, ".f4v") || |
| 822 !strcmp(fname + strlen(fname) - 4, ".mp4"))) { | 856 !strcmp(fname + strlen(fname) - 4, ".mp4"))) { |
| 823 memcpy(rt->playpath, "mp4:", 5); | 857 memcpy(rt->playpath, "mp4:", 5); |
| 824 } else { | 858 } else { |
| 825 rt->playpath[0] = 0; | 859 rt->playpath[0] = 0; |
| 826 } | 860 } |
| 827 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5); | 861 strncat(rt->playpath, fname, sizeof(rt->playpath) - 5); |
| 828 | 862 |
| 863 rt->client_report_size = 1048576; |
| 864 rt->bytes_read = 0; |
| 865 rt->last_bytes_read = 0; |
| 866 |
| 829 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname =
%s\n", | 867 av_log(LOG_CONTEXT, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname =
%s\n", |
| 830 proto, path, rt->app, rt->playpath); | 868 proto, path, rt->app, rt->playpath); |
| 831 gen_connect(s, rt, proto, hostname, port); | 869 gen_connect(s, rt, proto, hostname, port); |
| 832 | 870 |
| 833 do { | 871 do { |
| 834 ret = get_packet(s, 1); | 872 ret = get_packet(s, 1); |
| 835 } while (ret == EAGAIN); | 873 } while (ret == EAGAIN); |
| 836 if (ret < 0) | 874 if (ret < 0) |
| 837 goto fail; | 875 goto fail; |
| 838 | 876 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 950 } | 988 } |
| 951 | 989 |
| 952 URLProtocol rtmp_protocol = { | 990 URLProtocol rtmp_protocol = { |
| 953 "rtmp", | 991 "rtmp", |
| 954 rtmp_open, | 992 rtmp_open, |
| 955 rtmp_read, | 993 rtmp_read, |
| 956 rtmp_write, | 994 rtmp_write, |
| 957 NULL, /* seek */ | 995 NULL, /* seek */ |
| 958 rtmp_close, | 996 rtmp_close, |
| 959 }; | 997 }; |
| OLD | NEW |