static int per_client_init(RTSPContext *ctx) { int i; AVOutputFormat *fmt; // if((fmt = av_guess_format("rtp", NULL, NULL)) == NULL) { ga_error("RTP not supported.\n"); return -1; } if((ctx->sdp_fmtctx = avformat_alloc_context()) == NULL) { ga_error("create avformat context failed.\n"); return -1; } ctx->sdp_fmtctx->oformat = fmt; // video stream for(i = 0; i < video_source_channels(); i++) { if((ctx->sdp_vstream[i] = ga_avformat_new_stream( ctx->sdp_fmtctx, i, rtspconf->video_encoder_codec)) == NULL) { // ga_error("cannot create new video stream (%d:%d)\n", i, rtspconf->video_encoder_codec->id); return -1; } if((ctx->sdp_vencoder[i] = ga_avcodec_vencoder_init( ctx->sdp_vstream[i]->codec, rtspconf->video_encoder_codec, video_source_width(i), video_source_height(i), rtspconf->video_fps, rtspconf->vso)) == NULL) { // ga_error("cannot init video encoder\n"); return -1; } } // audio stream #ifdef ENABLE_AUDIO if((ctx->sdp_astream = ga_avformat_new_stream( ctx->sdp_fmtctx, video_source_channels(), rtspconf->audio_encoder_codec)) == NULL) { ga_error("cannot create new audio stream (%d)\n", rtspconf->audio_encoder_codec->id); return -1; } if((ctx->sdp_aencoder = ga_avcodec_aencoder_init( ctx->sdp_astream->codec, rtspconf->audio_encoder_codec, rtspconf->audio_bitrate, rtspconf->audio_samplerate, rtspconf->audio_channels, rtspconf->audio_codec_format, rtspconf->audio_codec_channel_layout)) == NULL) { ga_error("cannot init audio encoder\n"); return -1; } #endif return 0; }
static void per_client_deinit(RTSPContext *ctx) { int i; for(i = 0; i < video_source_channels()+1; i++) { close_av(ctx->fmtctx[i], ctx->stream[i], ctx->encoder[i], ctx->lower_transport[i]); #ifdef HOLE_PUNCHING if(ctx->lower_transport[i] == RTSP_LOWER_TRANSPORT_UDP) rtp_close_ports(ctx, i); #endif } //close_av(ctx->fmtctx[0], ctx->stream[0], ctx->encoder[0], ctx->lower_transport[0]); //close_av(ctx->fmtctx[1], ctx->stream[1], ctx->encoder[1], ctx->lower_transport[1]); // #ifdef HOLE_PUNCHING if(ctx->sdp_fmtctx->pb) avio_close(ctx->sdp_fmtctx->pb); #endif close_av(ctx->sdp_fmtctx, NULL, NULL, RTSP_LOWER_TRANSPORT_UDP); // if(ctx->rbuffer) { free(ctx->rbuffer); } ctx->rbufsize = 0; ctx->rbufhead = ctx->rbuftail = 0; // return; }
static int vencoder_start(void *arg) { int iid; char *pipefmt = (char*) arg; #define MAXPARAMLEN 64 static char pipename[VIDEO_SOURCE_CHANNEL_MAX][MAXPARAMLEN]; #ifdef SAVEFILE if(fout == NULL) { fout = fopen(SAVEFILE, "wb"); } #endif if(vencoder_started != 0) return 0; vencoder_started = 1; for(iid = 0; iid < video_source_channels(); iid++) { snprintf(pipename[iid], MAXPARAMLEN, pipefmt, iid); if(pthread_create(&vencoder_tid[iid], NULL, vencoder_threadproc, pipename[iid]) != 0) { vencoder_started = 0; ga_error("video encoder: create thread failed.\n"); return -1; } } ga_error("video encdoer: all started (%d)\n", iid); return 0; }
static int vencoder_deinit(void *arg) { int iid; for(iid = 0; iid < video_source_channels(); iid++) { if(_sps[iid] != NULL) free(_sps[iid]); if(_pps[iid] != NULL) free(_pps[iid]); #ifdef STANDALONE_SDP if(vencoder_sdp[iid] != NULL) ga_avcodec_close(vencoder_sdp[iid]); #endif if(vencoder[iid] != NULL) ga_avcodec_close(vencoder[iid]); #ifdef STANDALONE_SDP vencoder_sdp[iid] = NULL; #endif vencoder[iid] = NULL; } bzero(_sps, sizeof(_sps)); bzero(_pps, sizeof(_pps)); bzero(_spslen, sizeof(_spslen)); bzero(_ppslen, sizeof(_ppslen)); vencoder_initialized = 0; ga_error("video encoder: deinitialized.\n"); return 0; }
static int vencoder_stop(void *arg) { int iid; void *ignored; if(vencoder_started == 0) return 0; vencoder_started = 0; for(iid = 0; iid < video_source_channels(); iid++) { pthread_join(vencoder_tid[iid], &ignored); } ga_error("video encdoer: all stopped (%d)\n", iid); return 0; }
static int vencoder_deinit(void *arg) { int iid; for(iid = 0; iid < video_source_channels(); iid++) { if(_sps[iid] != NULL) free(_sps[iid]); if(_pps[iid] != NULL) free(_pps[iid]); vpu_encoder_deinit(&vpu[iid]); } // bzero(_sps, sizeof(_sps)); bzero(_pps, sizeof(_pps)); bzero(_spslen, sizeof(_spslen)); bzero(_ppslen, sizeof(_ppslen)); bzero(vencoder_tid, sizeof(vencoder_tid)); // vencoder_initialized = 0; ga_error("video encoder: VPU deinitialized.\n"); return 0; }
static int vencoder_init(void *arg) { int iid; char *pipefmt = (char*) arg; struct RTSPConf *rtspconf = rtspconf_global(); // if(rtspconf == NULL) { ga_error("video encoder: no configuration found\n"); return -1; } if(vencoder_initialized != 0) return 0; // for(iid = 0; iid < video_source_channels(); iid++) { char pipename[64]; int outputW, outputH; pipeline *pipe; // _sps[iid] = _pps[iid] = NULL; _spslen[iid] = _ppslen[iid] = 0; snprintf(pipename, sizeof(pipename), pipefmt, iid); outputW = video_source_out_width(iid); outputH = video_source_out_height(iid); if((pipe = pipeline::lookup(pipename)) == NULL) { ga_error("video encoder: pipe %s is not found\n", pipename); goto init_failed; } ga_error("video encoder: video source #%d from '%s' (%dx%d).\n", iid, pipe->name(), outputW, outputH, iid); // if(vpu_encoder_init(&vpu[iid], outputW, outputH, rtspconf->video_fps, 1, ga_conf_mapreadint("video-specific", "b") / 1000, ga_conf_mapreadint("video-specific", "g")) < 0) goto init_failed; } vencoder_initialized = 1; ga_error("video encoder: initialized (%d channels).\n", iid); return 0; init_failed: vencoder_deinit(NULL); return -1; }
static void rtsp_cmd_setup(RTSPContext *ctx, const char *url, RTSPMessageHeader *h) { int i; RTSPTransportField *th; struct sockaddr_in destaddr, myaddr; #ifdef WIN32 int destaddrlen, myaddrlen; #else socklen_t destaddrlen, myaddrlen; #endif char path[4096]; char channelname[VIDEO_SOURCE_CHANNEL_MAX+1][RTSP_STREAM_FORMAT_MAXLEN]; int baselen = strlen(rtspconf->object); int streamid; int rtp_port, rtcp_port; enum RTSPStatusCode errcode; // av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path, sizeof(path), url); for(i = 0; i < VIDEO_SOURCE_CHANNEL_MAX+1; i++) { snprintf(channelname[i], RTSP_STREAM_FORMAT_MAXLEN, RTSP_STREAM_FORMAT, i); } // if(strncmp(path, rtspconf->object, baselen) != 0) { ga_error("invalid object (path=%s)\n", path); rtsp_reply_error(ctx, RTSP_STATUS_AGGREGATE); return; } for(i = 0; i < VIDEO_SOURCE_CHANNEL_MAX+1; i++) { if(strcmp(path+baselen+1, channelname[i]) == 0) { streamid = i; break; } } if(i == VIDEO_SOURCE_CHANNEL_MAX+1) { // not found ga_error("invalid service (path=%s)\n", path); rtsp_reply_error(ctx, RTSP_STATUS_SERVICE); return; } // if(ctx->state != SERVER_STATE_IDLE && ctx->state != SERVER_STATE_READY) { rtsp_reply_error(ctx, RTSP_STATUS_STATE); return; } // create session id? if(ctx->session_id == NULL) { if(h->session_id[0] == '\0') { snprintf(h->session_id, sizeof(h->session_id), "%04x%04x", rand()%0x0ffff, rand()%0x0ffff); ctx->session_id = strdup(h->session_id); ga_error("New session created (id = %s)\n", ctx->session_id); } } // session id must match -- we have only one session if(ctx->session_id == NULL || strcmp(ctx->session_id, h->session_id) != 0) { ga_error("Bad session id %s != %s\n", h->session_id, ctx->session_id); errcode = RTSP_STATUS_SESSION; goto error_setup; } // find supported transport if((th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP)) == NULL) { th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP); } if(th == NULL) { ga_error("Cannot find transport\n"); errcode = RTSP_STATUS_TRANSPORT; goto error_setup; } // destaddrlen = sizeof(destaddr); bzero(&destaddr, destaddrlen); if(getpeername(ctx->fd, (struct sockaddr*) &destaddr, &destaddrlen) < 0) { ga_error("Cannot get peername\n"); errcode = RTSP_STATUS_INTERNAL; goto error_setup; } destaddr.sin_port = htons(th->client_port_min); // myaddrlen = sizeof(myaddr); bzero(&myaddr, myaddrlen); if(getsockname(ctx->fd, (struct sockaddr*) &myaddr, &myaddrlen) < 0) { ga_error("Cannot get sockname\n"); errcode = RTSP_STATUS_INTERNAL; goto error_setup; } // ctx->lower_transport[streamid] = th->lower_transport; if(rtp_new_av_stream(ctx, &destaddr, streamid, streamid == video_source_channels()/*rtspconf->audio_id*/ ? rtspconf->audio_encoder_codec->id : rtspconf->video_encoder_codec->id) < 0) { ga_error("Create AV stream %d failed.\n", streamid); errcode = RTSP_STATUS_TRANSPORT; goto error_setup; } // ctx->state = SERVER_STATE_READY; rtsp_reply_header(ctx, RTSP_STATUS_OK); rtsp_printf(ctx, "Session: %s\r\n", ctx->session_id); switch(th->lower_transport) { case RTSP_LOWER_TRANSPORT_UDP: #ifdef HOLE_PUNCHING rtp_port = ctx->rtpLocalPort[streamid*2]; rtcp_port = ctx->rtpLocalPort[streamid*2+1]; ctx->rtpPeerPort[streamid*2] = htons(th->client_port_min); ctx->rtpPeerPort[streamid*2+1] = htons(th->client_port_max); #else rtp_port = ff_rtp_get_local_rtp_port((URLContext*) ctx->fmtctx[streamid]->pb->opaque); rtcp_port = ff_rtp_get_local_rtcp_port((URLContext*) ctx->fmtctx[streamid]->pb->opaque); #endif ga_error("RTP/UDP: streamid=%d; client=%d-%d; server=%d-%d\n", streamid, th->client_port_min, th->client_port_max, rtp_port, rtcp_port); rtsp_printf(ctx, "Transport: RTP/AVP/UDP;unicast;client_port=%d-%d;server_port=%d-%d\r\n", th->client_port_min, th->client_port_max, rtp_port, rtcp_port); break; case RTSP_LOWER_TRANSPORT_TCP: ga_error("RTP/TCP: interleaved=%d-%d\n", streamid*2, streamid*2+1); rtsp_printf(ctx, "Transport: RTP/AVP/TCP;unicast;interleaved=%d-%d\r\n", streamid*2, streamid*2+1, streamid*2); break; default: // should not happen break; } rtsp_printf(ctx, "\r\n"); return; error_setup: if(ctx->session_id != NULL) { free(ctx->session_id); ctx->session_id = NULL; } if(ctx->encoder[streamid] != NULL) { ctx->encoder[streamid] = NULL; } if(ctx->stream[streamid] != NULL) { ctx->stream[streamid] = NULL; } if(ctx->fmtctx[streamid] != NULL) { avformat_free_context(ctx->fmtctx[streamid]); ctx->fmtctx[streamid] = NULL; } rtsp_reply_error(ctx, errcode); return; }
static int vencoder_init(void *arg) { int iid; char *pipefmt = (char*) arg; struct RTSPConf *rtspconf = rtspconf_global(); // if(rtspconf == NULL) { ga_error("video encoder: no configuration found\n"); return -1; } if(vencoder_initialized != 0) return 0; // for(iid = 0; iid < video_source_channels(); iid++) { char pipename[64]; int outputW, outputH; pipeline *pipe; // _sps[iid] = _pps[iid] = NULL; _spslen[iid] = _ppslen[iid] = 0; snprintf(pipename, sizeof(pipename), pipefmt, iid); outputW = video_source_out_width(iid); outputH = video_source_out_height(iid); if((pipe = pipeline::lookup(pipename)) == NULL) { ga_error("video encoder: pipe %s is not found\n", pipename); goto init_failed; } ga_error("video encoder: video source #%d from '%s' (%dx%d).\n", iid, pipe->name(), outputW, outputH, iid); vencoder[iid] = ga_avcodec_vencoder_init(NULL, rtspconf->video_encoder_codec, outputW, outputH, rtspconf->video_fps, rtspconf->vso); if(vencoder[iid] == NULL) goto init_failed; #ifdef STANDALONE_SDP // encoders for SDP generation switch(rtspconf->video_encoder_codec->id) { case AV_CODEC_ID_H264: case AV_CODEC_ID_H265: case AV_CODEC_ID_CAVS: case AV_CODEC_ID_MPEG4: // need ctx with CODEC_FLAG_GLOBAL_HEADER flag avc = avcodec_alloc_context3(rtspconf->video_encoder_codec); if(avc == NULL) goto init_failed; avc->flags |= CODEC_FLAG_GLOBAL_HEADER; avc = ga_avcodec_vencoder_init(avc, rtspconf->video_encoder_codec, outputW, outputH, rtspconf->video_fps, rtspconf->vso); if(avc == NULL) goto init_failed; ga_error("video encoder: meta-encoder #%d created.\n", iid); break; default: // do nothing break; } vencoder_sdp[iid] = avc; #endif } vencoder_initialized = 1; ga_error("video encoder: initialized.\n"); return 0; init_failed: vencoder_deinit(NULL); return -1; }