Ejemplo n.º 1
0
static switch_status_t do_write_video(switch_file_handle_t *handle, switch_frame_t *frame)
{
	uint32_t datalen = frame->datalen;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	int is_iframe = 0;
	uint8_t *hdr = NULL;
	uint8_t start_bit;
	uint32_t used;
	bool is_key = false;
	webm_file_context_t *context = (webm_file_context_t *)handle->private_info;

	hdr = (uint8_t *)frame->data;

	switch_assert(frame->img);

	// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x | len:%d m:%d st:%d i:%d\n", hdr[0], hdr[1], hdr[2], datalen, frame->m, start_bit, is_iframe);

	

	if (!context->video) {
		context->video_track_id = context->segment->AddVideoTrack(frame->img->d_w, frame->img->d_h, 0);
		if (!context->video_track_id) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error add video track!\n");
			switch_goto_status(SWITCH_STATUS_FALSE, end);
		}
		context->video = static_cast<mkvmuxer::VideoTrack*>(context->segment->GetTrackByNumber(context->video_track_id));
		context->video->SetStereoMode(0);
		context->video->set_codec_id("V_VP8");
		context->video->set_uid(0xDEADBEEF); // debug ?
	}

	buffer_vp8_packets(context, frame, &is_key);

	if (frame->m && (used = switch_buffer_inuse(context->buf))) {
		const void *data;
		int duration = 0;

		
		switch_buffer_peek_zerocopy(context->buf, &data);
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VID samplecount: %u\n", context->timer.samplecount);

		switch_mutex_lock(context->mutex);
		switch_core_timer_sync(&context->timer);
		bool ret = false;
		ret = context->segment->AddFrame((const uint8_t *)data, used, context->video_track_id, context->timer.samplecount * 1000LL, is_key);
		switch_mutex_unlock(context->mutex);

		if (!ret) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error add frame %d bytes, timecode: %llu\n", used, context->timer.samplecount * 1000LL);
			switch_goto_status(SWITCH_STATUS_FALSE, end);
		}

		switch_buffer_zero(context->buf);
	}

end:
	

	return status;
}
Ejemplo n.º 2
0
void *SWITCH_THREAD_FUNC rtmp_io_tcp_thread(switch_thread_t *thread, void *obj)
{
	rtmp_io_tcp_t *io = (rtmp_io_tcp_t*)obj;
	io->base.running = 1;
	
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: I/O Thread starting\n", io->base.profile->name);
	
	
	while(io->base.running) {
		const switch_pollfd_t *fds;
		int32_t numfds;
		int32_t i;
		switch_status_t status;
		
		switch_mutex_lock(io->mutex);
		status = switch_pollset_poll(io->pollset, 500000, &numfds, &fds);
		switch_mutex_unlock(io->mutex);
		
		if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_TIMEOUT) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "pollset_poll failed\n");
			continue;
		} else if (status == SWITCH_STATUS_TIMEOUT) {
			switch_cond_next();
		}
		
		for (i = 0; i < numfds; i++) {
			if (!fds[i].client_data) { 
				switch_socket_t *newsocket;
				if (switch_socket_accept(&newsocket, io->listen_socket, io->base.pool) != SWITCH_STATUS_SUCCESS) {
					if (io->base.running) {
						/* Don't spam the logs if we are shutting down */
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error [%s]\n", strerror(errno));	
					} else {
						return NULL;
					}
				} else {
					rtmp_session_t *rsession;
					
					if (switch_socket_opt_set(newsocket, SWITCH_SO_NONBLOCK, TRUE)) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't set socket as non-blocking\n");
					}

					if (switch_socket_opt_set(newsocket, SWITCH_SO_TCP_NODELAY, 1)) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Couldn't disable Nagle.\n");
					}
					
					if (rtmp_session_request(io->base.profile, &rsession) != SWITCH_STATUS_SUCCESS) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTMP session request failed\n");
						switch_socket_close(newsocket);
					} else {
						switch_sockaddr_t *addr = NULL;
						char ipbuf[200];
						
						/* Create out private data and attach it to the rtmp session structure */
						rtmp_tcp_io_private_t *pvt = switch_core_alloc(rsession->pool, sizeof(*pvt));
						rsession->io_private = pvt;
						pvt->socket = newsocket;
						switch_socket_create_pollfd(&pvt->pollfd, newsocket, SWITCH_POLLIN | SWITCH_POLLERR, rsession, rsession->pool);
						switch_pollset_add(io->pollset, pvt->pollfd);
						switch_buffer_create_dynamic(&pvt->sendq, 512, 1024, 0);
						
						/* Get the remote address/port info */
						switch_socket_addr_get(&addr, SWITCH_TRUE, newsocket);
						switch_get_addr(ipbuf, sizeof(ipbuf), addr);
						rsession->remote_address = switch_core_strdup(rsession->pool, ipbuf);
						rsession->remote_port = switch_sockaddr_get_port(addr);
						switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_INFO, "Rtmp connection from %s:%i\n",
										  rsession->remote_address, rsession->remote_port);
					}
				}
			} else {
				rtmp_session_t *rsession = (rtmp_session_t*)fds[i].client_data;
				rtmp_tcp_io_private_t *io_pvt = (rtmp_tcp_io_private_t*)rsession->io_private;
				
				if (fds[i].rtnevents & SWITCH_POLLOUT && switch_buffer_inuse(io_pvt->sendq) > 0) {
					/* Send as much remaining data as possible */
					switch_size_t sendlen;
					const void *ptr;
					sendlen = switch_buffer_peek_zerocopy(io_pvt->sendq, &ptr);
					switch_socket_send_nonblock(io_pvt->socket, ptr, &sendlen);
					switch_buffer_toss(io_pvt->sendq, sendlen);
					if (switch_buffer_inuse(io_pvt->sendq) == 0) {
						/* Remove our fd from OUT polling */
						rtmp_tcp_alter_pollfd(rsession, SWITCH_FALSE);
					}
				} else 	if (fds[i].rtnevents & SWITCH_POLLIN && rtmp_handle_data(rsession) != SWITCH_STATUS_SUCCESS) {
					switch_log_printf(SWITCH_CHANNEL_UUID_LOG(rsession->uuid), SWITCH_LOG_DEBUG, "Closing socket\n");
					
					switch_mutex_lock(io->mutex);
					switch_pollset_remove(io->pollset, io_pvt->pollfd);
					switch_mutex_unlock(io->mutex);
					
					switch_socket_close(io_pvt->socket);
					io_pvt->socket = NULL;
					
					rtmp_session_destroy(&rsession);
				}
			}
		}
	}
	
	io->base.running = -1;
	switch_socket_close(io->listen_socket);
	
	return NULL;
}
Ejemplo n.º 3
0
static switch_status_t do_write_video(switch_file_handle_t *handle, switch_frame_t *frame)
{
	uint32_t datalen = frame->datalen;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	int is_iframe = 0;
	uint32_t size;
	uint8_t *hdr = NULL;
	uint8_t fragment_type;
	uint8_t nal_type;
	uint8_t start_bit;
	mp4_file_context_t *context = handle->private_info;

	hdr = (uint8_t *)frame->data;
	fragment_type = hdr[0] & 0x1f;
	nal_type = hdr[1] & 0x1f;
	start_bit = hdr[1] & 0x80;
	is_iframe = (((fragment_type == 28 || fragment_type == 29) && nal_type == 5 && start_bit == 128) || fragment_type == 5 || fragment_type ==7 || fragment_type ==8) ? 1 : 0;

	// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%02x %02x %02x | len:%d m:%d st:%d i:%d\n", hdr[0], hdr[1], hdr[2], datalen, frame->m, start_bit, is_iframe);

	size = htonl(datalen);
	switch_buffer_write(context->buf, &size, 4);
	switch_buffer_write(context->buf, hdr, datalen);

	switch_mutex_lock(context->mutex);

	if (fragment_type == 7 && !context->sps_set) { //sps
		context->sps_set = 1;

		init_video_track(context->fd, &context->video, frame);
		if (context->video == MP4_INVALID_TRACK_ID) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error add video track!\n");
			switch_goto_status(SWITCH_STATUS_FALSE, end);
		}
	} else if (fragment_type == 8 && context->sps_set && !context->pps_set) { //pps
		MP4AddH264PictureParameterSet(context->fd, context->video, hdr, datalen);
		context->pps_set = 1;
	}

	if (nal_type == 7 || nal_type == 8 || frame->m == 0) {
	} else if (context->sps_set && context->pps_set) {
		uint32_t used = switch_buffer_inuse(context->buf);
		const void *data;
		int duration = 0;

		if (!context->timer.interval) {
			switch_core_timer_init(&context->timer, "soft", 1, 1, context->pool);
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "init timer\n");
		} else {
			switch_core_timer_sync(&context->timer);
		}

		duration = context->timer.samplecount - context->last_pts;

		// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "samplecount: %u, duration: %u\n", context->timer.samplecount, duration);
		switch_buffer_peek_zerocopy(context->buf, &data);

		if (context->last_pts == 0) { // first img, write at the very beginning so we don't see blank screen
			duration /= 2;
			MP4WriteSample(context->fd, context->video, data, used, duration, 0, is_iframe);

			if (duration > context->offset) {
				duration -= context->offset;
			} else {
				duration = 0;
			}
		}

		context->last_pts = context->timer.samplecount;

		// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "samplecount: %u, duration: %u\n", context->timer.samplecount, duration);

		if (duration) {
			MP4WriteSample(context->fd, context->video, data, used, duration, 0, is_iframe);
		}
		switch_buffer_zero(context->buf);
	}

end:
	switch_mutex_unlock(context->mutex);

	return status;
}
Ejemplo n.º 4
0
static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *frame)
{
	vpx_context_t *context = (vpx_context_t *)codec->private_info;
	switch_size_t len;
	vpx_codec_ctx_t *decoder = NULL;
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	int is_start = 0, is_keyframe = 0, get_refresh = 0;

	if (context->is_vp9) {
		is_start = is_keyframe = IS_VP9_KEY_FRAME(*(unsigned char *)frame->data);
	} else { // vp8
		is_start = (*(unsigned char *)frame->data & 0x10);
		is_keyframe = IS_VP8_KEY_FRAME((uint8_t *)frame->data);
	}

	// if (is_keyframe) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got key %d\n", is_keyframe);

	if (context->need_decoder_reset != 0) {
		vpx_codec_destroy(&context->decoder);
		context->decoder_init = 0;
		init_decoder(codec);
		context->need_decoder_reset = 0;
	}
	
	if (!context->decoder_init) {
		init_decoder(codec);
	}

	if (!context->decoder_init) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "VPX decoder is not initialized!\n");
		return SWITCH_STATUS_FALSE;
	}

	decoder = &context->decoder;
	
	// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "len: %d ts: %u mark:%d\n", frame->datalen, frame->timestamp, frame->m);

	// context->last_received_timestamp = frame->timestamp;
	context->last_received_complete_picture = frame->m ? SWITCH_TRUE : SWITCH_FALSE;

	if (is_start) {
		context->got_start_frame = 1;
	}
	
	if (is_keyframe) {
		if (context->got_key_frame <= 0) {
			context->got_key_frame = 1;
			if (!is_keyframe) {
				get_refresh = 1;
			}
		} else {
			context->got_key_frame++;
		}
	} else if (context->got_key_frame <= 0) {
		if ((--context->got_key_frame % 200) == 0) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Waiting for key frame %d\n", context->got_key_frame);
		}
		if (!context->got_start_frame) {
			switch_goto_status(SWITCH_STATUS_MORE_DATA, end);
		}
	}


	status = context->is_vp9 ? buffer_vp9_packets(context, frame) : buffer_vp8_packets(context, frame);


	if (context->dec_iter && (frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter))) {
		switch_goto_status(SWITCH_STATUS_SUCCESS, end);
	}

	//printf("READ buf:%ld got_key:%d st:%d m:%d\n", switch_buffer_inuse(context->vpx_packet_buffer), context->got_key_frame, status, frame->m);

	len = switch_buffer_inuse(context->vpx_packet_buffer);

	//if (frame->m && (status != SWITCH_STATUS_SUCCESS || !len)) {
		//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "WTF????? %d %ld\n", status, len);
	//}


	if (status == SWITCH_STATUS_SUCCESS && frame->m && len) {
		uint8_t *data;
		int corrupted = 0;
		int err;

		switch_buffer_peek_zerocopy(context->vpx_packet_buffer, (void *)&data);

		context->dec_iter = NULL;
		err = vpx_codec_decode(decoder, data, (unsigned int)len, NULL, 0);

		if (err != VPX_CODEC_OK) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Error decoding %" SWITCH_SIZE_T_FMT " bytes, [%d:%s:%s]\n",
							  len, err, vpx_codec_error(decoder), vpx_codec_error_detail(decoder));
			switch_goto_status(SWITCH_STATUS_RESTART, end);
		}

		if (vpx_codec_control(decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted) != VPX_CODEC_OK) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "VPX control error!\n");
			switch_goto_status(SWITCH_STATUS_RESTART, end);
		}
		
		if (corrupted) {
			frame->img = NULL;
		} else {
			frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &context->dec_iter);
		}
		
		switch_buffer_zero(context->vpx_packet_buffer);
		
		if (!frame->img) {
			//context->need_decoder_reset = 1;
			context->got_key_frame = 0;
			context->got_start_frame = 0;
			status = SWITCH_STATUS_RESTART;
		}
	}

end:

	if (status == SWITCH_STATUS_RESTART) {
		switch_buffer_zero(context->vpx_packet_buffer);
		//context->need_decoder_reset = 1;
		context->got_key_frame = 0;
		context->got_start_frame = 0;
		//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "RESET VPX\n");
	}

	if (!frame->img || status == SWITCH_STATUS_RESTART) {
		status = SWITCH_STATUS_MORE_DATA;
	}

	if (context->got_key_frame <= 0 || get_refresh) {
		switch_set_flag(frame, SFF_WAIT_KEY_FRAME);
	}

	return status;
}