| @@ -1764,13 +1764,84 @@ static int handle_invoke_error(URLContext *s, RTMPPacket *pkt) | |||
| return ret; | |||
| } | |||
| static int write_begin(URLContext *s) | |||
| { | |||
| RTMPContext *rt = s->priv_data; | |||
| PutByteContext pbc; | |||
| RTMPPacket spkt = { 0 }; | |||
| int ret; | |||
| // Send Stream Begin 1 | |||
| if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL, | |||
| RTMP_PT_PING, 0, 6)) < 0) { | |||
| av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); | |||
| return ret; | |||
| } | |||
| bytestream2_init_writer(&pbc, spkt.data, spkt.size); | |||
| bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin | |||
| bytestream2_put_be32(&pbc, rt->nb_streamid); | |||
| ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, | |||
| rt->prev_pkt[1]); | |||
| ff_rtmp_packet_destroy(&spkt); | |||
| return ret; | |||
| } | |||
| static int write_status(URLContext *s, RTMPPacket *pkt, | |||
| const char *status, const char *filename) | |||
| { | |||
| RTMPContext *rt = s->priv_data; | |||
| RTMPPacket spkt = { 0 }; | |||
| char statusmsg[128]; | |||
| uint8_t *pp; | |||
| int ret; | |||
| if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, | |||
| RTMP_PT_INVOKE, 0, | |||
| RTMP_PKTDATA_DEFAULT_SIZE)) < 0) { | |||
| av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); | |||
| return ret; | |||
| } | |||
| pp = spkt.data; | |||
| spkt.extra = pkt->extra; | |||
| ff_amf_write_string(&pp, "onStatus"); | |||
| ff_amf_write_number(&pp, 0); | |||
| ff_amf_write_null(&pp); | |||
| ff_amf_write_object_start(&pp); | |||
| ff_amf_write_field_name(&pp, "level"); | |||
| ff_amf_write_string(&pp, "status"); | |||
| ff_amf_write_field_name(&pp, "code"); | |||
| ff_amf_write_string(&pp, status); | |||
| ff_amf_write_field_name(&pp, "description"); | |||
| snprintf(statusmsg, sizeof(statusmsg), | |||
| "%s is now published", filename); | |||
| ff_amf_write_string(&pp, statusmsg); | |||
| ff_amf_write_field_name(&pp, "details"); | |||
| ff_amf_write_string(&pp, filename); | |||
| ff_amf_write_field_name(&pp, "clientid"); | |||
| snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT); | |||
| ff_amf_write_string(&pp, statusmsg); | |||
| ff_amf_write_object_end(&pp); | |||
| spkt.size = pp - spkt.data; | |||
| ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, | |||
| rt->prev_pkt[1]); | |||
| ff_rtmp_packet_destroy(&spkt); | |||
| return ret; | |||
| } | |||
| static int send_invoke_response(URLContext *s, RTMPPacket *pkt) | |||
| { | |||
| RTMPContext *rt = s->priv_data; | |||
| double seqnum; | |||
| char filename[64]; | |||
| char command[64]; | |||
| char statusmsg[128]; | |||
| int stringlen; | |||
| char *pchar; | |||
| const uint8_t *p = pkt->data; | |||
| @@ -1823,52 +1894,13 @@ static int send_invoke_response(URLContext *s, RTMPPacket *pkt) | |||
| pp = spkt.data; | |||
| ff_amf_write_string(&pp, "onFCPublish"); | |||
| } else if (!strcmp(command, "publish")) { | |||
| PutByteContext pbc; | |||
| // Send Stream Begin 1 | |||
| if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL, | |||
| RTMP_PT_PING, 0, 6)) < 0) { | |||
| av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); | |||
| return ret; | |||
| } | |||
| pp = spkt.data; | |||
| bytestream2_init_writer(&pbc, pp, spkt.size); | |||
| bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin | |||
| bytestream2_put_be32(&pbc, rt->nb_streamid); | |||
| ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size, | |||
| rt->prev_pkt[1]); | |||
| ff_rtmp_packet_destroy(&spkt); | |||
| ret = write_begin(s); | |||
| if (ret < 0) | |||
| return ret; | |||
| // Send onStatus(NetStream.Publish.Start) | |||
| if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, | |||
| RTMP_PT_INVOKE, 0, | |||
| RTMP_PKTDATA_DEFAULT_SIZE)) < 0) { | |||
| av_log(s, AV_LOG_ERROR, "Unable to create response packet\n"); | |||
| return ret; | |||
| } | |||
| spkt.extra = pkt->extra; | |||
| pp = spkt.data; | |||
| ff_amf_write_string(&pp, "onStatus"); | |||
| ff_amf_write_number(&pp, 0); | |||
| ff_amf_write_null(&pp); | |||
| ff_amf_write_object_start(&pp); | |||
| ff_amf_write_field_name(&pp, "level"); | |||
| ff_amf_write_string(&pp, "status"); | |||
| ff_amf_write_field_name(&pp, "code"); | |||
| ff_amf_write_string(&pp, "NetStream.Publish.Start"); | |||
| ff_amf_write_field_name(&pp, "description"); | |||
| snprintf(statusmsg, sizeof(statusmsg), | |||
| "%s is now published", filename); | |||
| ff_amf_write_string(&pp, statusmsg); | |||
| ff_amf_write_field_name(&pp, "details"); | |||
| ff_amf_write_string(&pp, filename); | |||
| ff_amf_write_field_name(&pp, "clientid"); | |||
| snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT); | |||
| ff_amf_write_string(&pp, statusmsg); | |||
| ff_amf_write_object_end(&pp); | |||
| return write_status(s, pkt, "NetStream.Publish.Start", | |||
| filename); | |||
| } else { | |||
| if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL, | |||
| RTMP_PT_INVOKE, 0, | |||