/* used only when posting data */ static int http_write(URLContext *h, uint8_t *buf, int size) { char temp[11]; /* 32-bit hex + CRLF + nul */ int ret; char crlf[] = "\r\n"; HTTPContext *s = h->priv_data; if (s->chunksize == -1) { /* headers are sent without any special encoding */ return url_write(s->hd, buf, size); } /* silently ignore zero-size data since chunk encoding that would * signal EOF */ if (size > 0) { /* upload data using chunked encoding */ snprintf(temp, sizeof(temp), "%x\r\n", size); if ((ret = url_write(s->hd, temp, strlen(temp))) < 0 || (ret = url_write(s->hd, buf, size)) < 0 || (ret = url_write(s->hd, crlf, sizeof(crlf) - 1)) < 0) return ret; } return size; }
int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, int chunk_size, RTMPPacket *prev_pkt) { uint8_t pkt_hdr[16], *p = pkt_hdr; int mode = RTMP_PS_TWELVEBYTES; int off = 0; //TODO: header compression bytestream_put_byte(&p, pkt->channel_id | (mode << 6)); if (mode != RTMP_PS_ONEBYTE) { bytestream_put_be24(&p, pkt->timestamp); if (mode != RTMP_PS_FOURBYTES) { bytestream_put_be24(&p, pkt->data_size); bytestream_put_byte(&p, pkt->type); if (mode == RTMP_PS_TWELVEBYTES) bytestream_put_le32(&p, pkt->extra); } } url_write(h, pkt_hdr, p-pkt_hdr); while (off < pkt->data_size) { int towrite = FFMIN(chunk_size, pkt->data_size - off); url_write(h, pkt->data + off, towrite); off += towrite; if (off < pkt->data_size) { uint8_t marker = 0xC0 | pkt->channel_id; url_write(h, &marker, 1); } } return 0; }
static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) { RTSPState *rt = s->priv_data; AVFormatContext *rtpctx = rtsp_st->transport_priv; uint8_t *buf, *ptr; int size; uint8_t interleave_header[4]; size = url_close_dyn_buf(rtpctx->pb, &buf); ptr = buf; while (size > 4) { uint32_t packet_len = AV_RB32(ptr); int id; ptr += 4; size -= 4; if (packet_len > size || packet_len < 2) break; if (ptr[1] >= 200 && ptr[1] <= 204) id = rtsp_st->interleaved_max; /* RTCP */ else id = rtsp_st->interleaved_min; /* RTP */ interleave_header[0] = '$'; interleave_header[1] = id; AV_WB16(interleave_header + 2, packet_len); url_write(rt->rtsp_hd, interleave_header, 4); url_write(rt->rtsp_hd, ptr, packet_len); ptr += packet_len; size -= packet_len; } av_free(buf); url_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE); return 0; }
static ssize_t exhaustive_send(URLContext *urlContext, uint8_t *packetized_data, int packetized_data_len) { uint8_t *ptr = packetized_data; uint8_t *end = packetized_data + packetized_data_len; ssize_t numBytes = 0; /* XXX: Do we need packet clock synchronization? I don't think so... */ while (ptr < end) { int remaining = end - ptr; int len; /* The size for each packet is actually encoded in the first 4 bytes of * each of a series of packets contained in `rtp_data'. */ assert(remaining >= 4); len = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3]; assert(len <= remaining - 4); ptr += 4; int n = url_write(urlContext, ptr, len); ptr += len; /* XXX: Our poor error handling comes courtesy of ffserver.c */ if (n > 0) { numBytes += n; } } return numBytes; }
static int rtp_write(URLContext *h, uint8_t *buf, int size) { RTPContext *s = h->priv_data; int ret; URLContext *hd; if (buf[1] >= 200 && buf[1] <= 204) { /* RTCP payload type */ hd = s->rtcp_hd; } else { /* RTP payload type */ hd = s->rtp_hd; } ret = url_write(hd, buf, size); #if 0 { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 10 * 1000000; nanosleep(&ts, NULL); } #endif return ret; }
/** Send a prepared MMST command packet. */ static int send_command_packet(MMSTContext *mmst) { MMSContext *mms = &mmst->mms; int len= mms->write_out_ptr - mms->out_buffer; int exact_length = FFALIGN(len, 8); int first_length= exact_length - 16; int len8= first_length/8; int write_result; // update packet length fields. AV_WL32(mms->out_buffer + 8, first_length); AV_WL32(mms->out_buffer + 16, len8); AV_WL32(mms->out_buffer + 32, len8-2); memset(mms->write_out_ptr, 0, exact_length - len); // write it out. write_result= url_write(mms->mms_hd, mms->out_buffer, exact_length); if(write_result != exact_length) { av_log(NULL, AV_LOG_ERROR, "Failed to write data of length %d: %d (%s)\n", exact_length, write_result, write_result < 0 ? strerror(write_result) : "The server closed the connection"); return AVERROR_IO; } return 0; }
static int md5_close(URLContext *h) { const char *filename = h->filename; uint8_t md5[16], buf[64]; URLContext *out; int i, err = 0; av_md5_final(h->priv_data, md5); for (i = 0; i < sizeof(md5); i++) snprintf(buf + i*2, 3, "%02x", md5[i]); buf[i*2] = '\n'; av_strstart(filename, "md5:", &filename); if (*filename) { err = url_open(&out, filename, URL_WRONLY); if (err) return err; err = url_write(out, buf, i*2+1); url_close(out); } else { if (fwrite(buf, 1, i*2+1, stdout) < i*2+1) err = AVERROR(errno); } return err; }
void rtp_send_punch_packets(URLContext* rtp_handle) { AVIOContext *pb; uint8_t *buf; int len; /* Send a small RTP packet */ if (url_open_dyn_buf(&pb) < 0) return; avio_w8(pb, (RTP_VERSION << 6)); avio_w8(pb, 0); /* Payload type */ avio_wb16(pb, 0); /* Seq */ avio_wb32(pb, 0); /* Timestamp */ avio_wb32(pb, 0); /* SSRC */ avio_flush(pb); len = url_close_dyn_buf(pb, &buf); if ((len > 0) && buf) url_write(rtp_handle, buf, len); av_free(buf); /* Send a minimal RTCP RR */ if (url_open_dyn_buf(&pb) < 0) return; avio_w8(pb, (RTP_VERSION << 6)); avio_w8(pb, RTCP_RR); /* receiver report */ avio_wb16(pb, 1); /* length in words - 1 */ avio_wb32(pb, 0); /* our own SSRC */ avio_flush(pb); len = url_close_dyn_buf(pb, &buf); if ((len > 0) && buf) url_write(rtp_handle, buf, len); av_free(buf); }
static int http_close(URLContext *h) { int ret = 0; char footer[] = "0\r\n\r\n"; HTTPContext *s = h->priv_data; /* signal end of chunked encoding if used */ if ((h->flags & URL_WRONLY) && s->chunksize != -1) { ret = url_write(s->hd, footer, sizeof(footer) - 1); ret = ret > 0 ? 0 : ret; } url_close(s->hd); av_free(s); return ret; }
/** Send a prepared MMST command packet. */ static int send_command_packet(MMSContext *mms) { int exact_length= mms->write_out_ptr - mms->out_buffer; int first_length= exact_length - 16; int len8= first_length/8; int write_result; // update packet length fields. AV_WL32(mms->out_buffer + 8, first_length); AV_WL32(mms->out_buffer + 16, len8); AV_WL32(mms->out_buffer + 32, len8-2); // write it out. write_result= url_write(mms->mms_hd, mms->out_buffer, exact_length); if(write_result != exact_length) { dprintf(NULL, "url_write returned: %d != %d\n", write_result, exact_length); return AVERROR_IO; } return 0; }
static int tcp_write_packet(AVFormatContext *s, RTSPStream *rtsp_st) { RTSPState *rt = s->priv_data; AVFormatContext *rtpctx = rtsp_st->transport_priv; uint8_t *buf, *ptr; int size; uint8_t *interleave_header, *interleaved_packet; size = url_close_dyn_buf(rtpctx->pb, &buf); ptr = buf; while (size > 4) { uint32_t packet_len = AV_RB32(ptr); int id; /* The interleaving header is exactly 4 bytes, which happens to be * the same size as the packet length header from * url_open_dyn_packet_buf. So by writing the interleaving header * over these bytes, we get a consecutive interleaved packet * that can be written in one call. */ interleaved_packet = interleave_header = ptr; ptr += 4; size -= 4; if (packet_len > size || packet_len < 2) break; if (ptr[1] >= RTCP_SR && ptr[1] <= RTCP_APP) id = rtsp_st->interleaved_max; /* RTCP */ else id = rtsp_st->interleaved_min; /* RTP */ interleave_header[0] = '$'; interleave_header[1] = id; AV_WB16(interleave_header + 2, packet_len); url_write(rt->rtsp_hd_out, interleaved_packet, 4 + packet_len); ptr += packet_len; size -= packet_len; } av_free(buf); url_open_dyn_packet_buf(&rtpctx->pb, RTSP_TCP_MAX_PACKET_SIZE); return 0; }
/***************************************************************************** * Write: *****************************************************************************/ static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer) { access_sys_t *p_sys = (access_sys_t*)p_access->p_sys; size_t i_write = 0; while (p_buffer != NULL) { block_t *p_next = p_buffer->p_next; #if LIBAVFORMAT_VERSION_MAJOR < 54 int written = url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer); if (written < 0) { errno = AVUNERROR(written); goto error; } i_write += written; #else avio_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer); avio_flush(p_sys->context); if (p_sys->context->error) { errno = AVUNERROR(p_sys->context->error); p_sys->context->error = 0; /* FIXME? */ goto error; } i_write += p_buffer->i_buffer; #endif block_Release(p_buffer); p_buffer = p_next; } return i_write; error: msg_Err(p_access, "Wrote only %zu bytes (%m)", i_write); block_ChainRelease( p_buffer ); return i_write; }
/***************************************************************************** * Write: *****************************************************************************/ static ssize_t Write(sout_access_out_t *p_access, block_t *p_buffer) { sout_access_out_sys_t *p_sys = (sout_access_out_sys_t*)p_access->p_sys; size_t i_write = 0; int val; while (p_buffer != NULL) { block_t *p_next = p_buffer->p_next; #if LIBAVFORMAT_VERSION_MAJOR < 54 val = url_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer); if (val < 0) goto error; i_write += val; #else avio_write(p_sys->context, p_buffer->p_buffer, p_buffer->i_buffer); avio_flush(p_sys->context); if ((val = p_sys->context->error) != 0) { p_sys->context->error = 0; /* FIXME? */ goto error; } i_write += p_buffer->i_buffer; #endif block_Release(p_buffer); p_buffer = p_next; } return i_write; error: msg_Err(p_access, "Wrote only %zu bytes: %s", i_write, vlc_strerror_c(AVUNERROR(val))); block_ChainRelease( p_buffer ); return i_write; }
static int write_buffer(stream_t *s, char *buffer, int len) { int r = url_write(s->priv, buffer, len); return (r <= 0) ? -1 : r; }
int rtp_check_and_send_back_rr(RTPDemuxContext *s, int count) { AVIOContext *pb; uint8_t *buf; int len; int rtcp_bytes; RTPStatistics *stats= &s->statistics; uint32_t lost; uint32_t extended_max; uint32_t expected_interval; uint32_t received_interval; uint32_t lost_interval; uint32_t expected; uint32_t fraction; uint64_t ntp_time= s->last_rtcp_ntp_time; // TODO: Get local ntp time? if (!s->rtp_ctx || (count < 1)) return -1; /* TODO: I think this is way too often; RFC 1889 has algorithm for this */ /* XXX: mpeg pts hardcoded. RTCP send every 0.5 seconds */ s->octet_count += count; rtcp_bytes = ((s->octet_count - s->last_octet_count) * RTCP_TX_RATIO_NUM) / RTCP_TX_RATIO_DEN; rtcp_bytes /= 50; // mmu_man: that's enough for me... VLC sends much less btw !? if (rtcp_bytes < 28) return -1; s->last_octet_count = s->octet_count; if (url_open_dyn_buf(&pb) < 0) return -1; // Receiver Report avio_w8(pb, (RTP_VERSION << 6) + 1); /* 1 report block */ avio_w8(pb, RTCP_RR); avio_wb16(pb, 7); /* length in words - 1 */ // our own SSRC: we use the server's SSRC + 1 to avoid conflicts avio_wb32(pb, s->ssrc + 1); avio_wb32(pb, s->ssrc); // server SSRC // some placeholders we should really fill... // RFC 1889/p64 extended_max= stats->cycles + stats->max_seq; expected= extended_max - stats->base_seq + 1; lost= expected - stats->received; lost= FFMIN(lost, 0xffffff); // clamp it since it's only 24 bits... expected_interval= expected - stats->expected_prior; stats->expected_prior= expected; received_interval= stats->received - stats->received_prior; stats->received_prior= stats->received; lost_interval= expected_interval - received_interval; if (expected_interval==0 || lost_interval<=0) fraction= 0; else fraction = (lost_interval<<8)/expected_interval; fraction= (fraction<<24) | lost; avio_wb32(pb, fraction); /* 8 bits of fraction, 24 bits of total packets lost */ avio_wb32(pb, extended_max); /* max sequence received */ avio_wb32(pb, stats->jitter>>4); /* jitter */ if(s->last_rtcp_ntp_time==AV_NOPTS_VALUE) { avio_wb32(pb, 0); /* last SR timestamp */ avio_wb32(pb, 0); /* delay since last SR */ } else { uint32_t middle_32_bits= s->last_rtcp_ntp_time>>16; // this is valid, right? do we need to handle 64 bit values special? uint32_t delay_since_last= ntp_time - s->last_rtcp_ntp_time; avio_wb32(pb, middle_32_bits); /* last SR timestamp */ avio_wb32(pb, delay_since_last); /* delay since last SR */ } // CNAME avio_w8(pb, (RTP_VERSION << 6) + 1); /* 1 report block */ avio_w8(pb, RTCP_SDES); len = strlen(s->hostname); avio_wb16(pb, (6 + len + 3) / 4); /* length in words - 1 */ avio_wb32(pb, s->ssrc); avio_w8(pb, 0x01); avio_w8(pb, len); avio_write(pb, s->hostname, len); // padding for (len = (6 + len) % 4; len % 4; len++) { avio_w8(pb, 0); } avio_flush(pb); len = url_close_dyn_buf(pb, &buf); if ((len > 0) && buf) { int result; av_dlog(s->ic, "sending %d bytes of RR\n", len); result= url_write(s->rtp_ctx, buf, len); av_dlog(s->ic, "result from url_write: %d\n", result); av_free(buf); } return 0; }
/* used only when posting data */ static int http_write(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; return url_write(s->hd, buf, size); }
static void rtsp_send_cmd(AVFormatContext *s, const char *cmd, RTSPHeader *reply, unsigned char **content_ptr) { RTSPState *rt = s->priv_data; char buf[4096], buf1[1024], *q; unsigned char ch; const char *p; int content_length, line_count; unsigned char *content = NULL; memset(reply, 0, sizeof(RTSPHeader)); rt->seq++; pstrcpy(buf, sizeof(buf), cmd); snprintf(buf1, sizeof(buf1), "CSeq: %d\r\n", rt->seq); pstrcat(buf, sizeof(buf), buf1); if (rt->session_id[0] != '\0' && !strstr(cmd, "\nIf-Match:")) { snprintf(buf1, sizeof(buf1), "Session: %s\r\n", rt->session_id); pstrcat(buf, sizeof(buf), buf1); } pstrcat(buf, sizeof(buf), "\r\n"); #ifdef DEBUG printf("Sending:\n%s--\n", buf); #endif url_write(rt->rtsp_hd, buf, strlen(buf)); /* parse reply (XXX: use buffers) */ line_count = 0; rt->last_reply[0] = '\0'; for(;;) { q = buf; for(;;) { if (url_readbuf(rt->rtsp_hd, &ch, 1) != 1) break; if (ch == '\n') break; if (ch == '$') { /* XXX: only parse it if first char on line ? */ rtsp_skip_packet(s); } else if (ch != '\r') { if ((q - buf) < sizeof(buf) - 1) *q++ = ch; } } *q = '\0'; #ifdef DEBUG printf("line='%s'\n", buf); #endif /* test if last line */ if (buf[0] == '\0') break; p = buf; if (line_count == 0) { /* get reply code */ get_word(buf1, sizeof(buf1), &p); get_word(buf1, sizeof(buf1), &p); reply->status_code = atoi(buf1); } else { rtsp_parse_line(reply, p); pstrcat(rt->last_reply, sizeof(rt->last_reply), p); pstrcat(rt->last_reply, sizeof(rt->last_reply), "\n"); } line_count++; } if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0') pstrcpy(rt->session_id, sizeof(rt->session_id), reply->session_id); content_length = reply->content_length; if (content_length > 0) { /* leave some room for a trailing '\0' (useful for simple parsing) */ content = av_malloc(content_length + 1); (void)url_readbuf(rt->rtsp_hd, content, content_length); content[content_length] = '\0'; } if (content_ptr) *content_ptr = content; }
static int http_connect(URLContext *h, const char *path, const char *hoststr, const char *auth, int *new_location) { HTTPContext *s = h->priv_data; int post, err; char line[1024]; char headers[1024] = ""; char *authstr = NULL; int64_t off = s->off; int len = 0; /* send http header */ post = h->flags & URL_WRONLY; authstr = ff_http_auth_create_response(&s->auth_state, auth, path, post ? "POST" : "GET"); /* set default headers if needed */ if (!has_header(s->headers, "\r\nUser-Agent: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, "User-Agent: %s\r\n", LIBAVFORMAT_IDENT); if (!has_header(s->headers, "\r\nAccept: ")) len += av_strlcpy(headers + len, "Accept: */*\r\n", sizeof(headers) - len); if (!has_header(s->headers, "\r\nRange: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, "Range: bytes=%"PRId64"-\r\n", s->off); if (!has_header(s->headers, "\r\nConnection: ")) len += av_strlcpy(headers + len, "Connection: close\r\n", sizeof(headers)-len); if (!has_header(s->headers, "\r\nHost: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, "Host: %s\r\n", hoststr); /* now add in custom headers */ av_strlcpy(headers+len, s->headers, sizeof(headers)-len); snprintf(s->buffer, sizeof(s->buffer), "%s %s HTTP/1.1\r\n" "%s" "%s" "%s" "\r\n", post ? "POST" : "GET", path, post && s->is_chunked ? "Transfer-Encoding: chunked\r\n" : "", headers, authstr ? authstr : ""); av_freep(&authstr); if (url_write(s->hd, s->buffer, strlen(s->buffer)) < 0) return AVERROR(EIO); /* init input buffer */ s->buf_ptr = s->buffer; s->buf_end = s->buffer; s->line_count = 0; s->off = 0; s->filesize = -1; s->chunksize = -1; if (post) { /* always use chunked encoding for upload data */ s->chunksize = 0; /* Pretend that it did work. We didn't read any header yet, since * we've still to send the POST data, but the code calling this * function will check http_code after we return. */ s->http_code = 200; return 0; } /* wait for header */ for(;;) { if (http_get_line(s, line, sizeof(line)) < 0) return AVERROR(EIO); dprintf(NULL, "header='%s'\n", line); err = process_line(h, line, s->line_count, new_location); if (err < 0) return err; if (err == 0) break; s->line_count++; } return (off == s->off) ? 0 : -1; }
int ff_rtmp_packet_write(URLContext *h, RTMPPacket *pkt, int chunk_size, RTMPPacket *prev_pkt) { uint8_t pkt_hdr[16], *p = pkt_hdr; int mode = RTMP_PS_TWELVEBYTES; int off = 0; int size = 0; pkt->ts_delta = pkt->timestamp - prev_pkt[pkt->channel_id].timestamp; //if channel_id = 0, this is first presentation of prev_pkt, send full hdr. if (prev_pkt[pkt->channel_id].channel_id && pkt->extra == prev_pkt[pkt->channel_id].extra) { if (pkt->type == prev_pkt[pkt->channel_id].type && pkt->data_size == prev_pkt[pkt->channel_id].data_size) { mode = RTMP_PS_FOURBYTES; if (pkt->ts_delta == prev_pkt[pkt->channel_id].ts_delta) mode = RTMP_PS_ONEBYTE; } else { mode = RTMP_PS_EIGHTBYTES; } } if (pkt->channel_id < 64) { bytestream_put_byte(&p, pkt->channel_id | (mode << 6)); } else if (pkt->channel_id < 64 + 256) { bytestream_put_byte(&p, 0 | (mode << 6)); bytestream_put_byte(&p, pkt->channel_id - 64); } else { bytestream_put_byte(&p, 1 | (mode << 6)); bytestream_put_le16(&p, pkt->channel_id - 64); } if (mode != RTMP_PS_ONEBYTE) { uint32_t timestamp = pkt->timestamp; if (mode != RTMP_PS_TWELVEBYTES) timestamp = pkt->ts_delta; bytestream_put_be24(&p, timestamp >= 0xFFFFFF ? 0xFFFFFF : timestamp); if (mode != RTMP_PS_FOURBYTES) { bytestream_put_be24(&p, pkt->data_size); bytestream_put_byte(&p, pkt->type); if (mode == RTMP_PS_TWELVEBYTES) bytestream_put_le32(&p, pkt->extra); } if (timestamp >= 0xFFFFFF) bytestream_put_be32(&p, timestamp); } // save history prev_pkt[pkt->channel_id].channel_id = pkt->channel_id; prev_pkt[pkt->channel_id].type = pkt->type; prev_pkt[pkt->channel_id].data_size = pkt->data_size; prev_pkt[pkt->channel_id].timestamp = pkt->timestamp; if (mode != RTMP_PS_TWELVEBYTES) { prev_pkt[pkt->channel_id].ts_delta = pkt->ts_delta; } else { prev_pkt[pkt->channel_id].ts_delta = pkt->timestamp; } prev_pkt[pkt->channel_id].extra = pkt->extra; url_write(h, pkt_hdr, p-pkt_hdr); size = p - pkt_hdr + pkt->data_size; while (off < pkt->data_size) { int towrite = FFMIN(chunk_size, pkt->data_size - off); url_write(h, pkt->data + off, towrite); off += towrite; if (off < pkt->data_size) { uint8_t marker = 0xC0 | pkt->channel_id; url_write(h, &marker, 1); size++; } } return size; }
static int gopher_write(URLContext *h, const uint8_t *buf, int size) { GopherContext *s = h->priv_data; return url_write(s->hd, buf, size); }