switch_core_video_thread_callback_func_t *_video_thread_callback;
void *_video_thread_user_data;
//switch_time_t last_video_write_time;
-
+
switch_image_write_callback_t image_write_callback;
void *image_write_callback_user_data;
};
DS_INVALID,
} dtls_state_t;
-typedef switch_status_t (switch_core_video_thread_callback_func_t) (switch_core_session_t *session, switch_frame_t *frame, void *user_data);
-
-
-
#define MESSAGE_STAMP_FFL(_m) _m->_file = __FILE__; _m->_func = __SWITCH_FUNC__; _m->_line = __LINE__
#define MESSAGE_STRING_ARG_MAX 10
*/
SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(_In_ switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags,
int stream_id);
-
-/*!
- \brief Write a video image to a session using a video frame
- \param session the session to write to
- \param frame a pointer to a frame to use for write with proper codec
- \param img the image structure with the image data
- \param the size for packetization
- \param flag pointer to frame flags to pass in / out
- \return SWITCH_STATUS_SUCCESS a if the image was written
-*/
-SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_image(switch_core_session_t *session, switch_frame_t *frame,
- switch_image_t *img, switch_size_t size, uint32_t *flag);
/*!
\brief set a callback to be called after each frame of an image is written
\param session the session to write to
/*!
\brief Encode video data using a codec handle
\param codec the codec handle to use
- \param img the img in I420 format
- \param encoded_data the buffer to write the encoded data to
- \param encoded_data_len the size of the encoded_data buffer
- \param flag flags to exchange
- \return SWITCH_STATUS_SUCCESS if the data was encoded
- \note encoded_data_len will be rewritten to the in-use size of encoded_data
+ \param frame the frame to encode
*/
-SWITCH_DECLARE(switch_status_t) switch_core_codec_encode_video(switch_codec_t *codec,
- switch_image_t *img,
- void *encoded_data, uint32_t *encoded_data_len, unsigned int *flag);
+SWITCH_DECLARE(switch_status_t) switch_core_codec_encode_video(switch_codec_t *codec, switch_frame_t *frame);
+
/*!
\brief send control data using a codec handle
\param flag flags to exchange
\return SWITCH_STATUS_SUCCESS if the data was decoded, and a non-NULL img
*/
-SWITCH_DECLARE(switch_status_t) switch_core_codec_decode_video(switch_codec_t *codec,
- switch_frame_t *frame,
- switch_image_t **img, unsigned int *flag);
-
+SWITCH_DECLARE(switch_status_t) switch_core_codec_decode_video(switch_codec_t *codec, switch_frame_t *frame);
/*!
\brief Destroy an initalized codec handle
*/
SWITCH_DECLARE(uint8_t) switch_core_session_check_interface(switch_core_session_t *session, const switch_endpoint_interface_t *endpoint_interface);
-/*!
- \brief Set a callback to let the core video thread call us
- \param session the session
- \param func to callback
- \param private user data
- \return SWITCH_STATUS_CONTINUE | SWITCH_STATUS_SUCCESS | SWITCH_STATUS_BREAK | SWITCH_STATUS_*
-
- If returns SWITCH_STATUS_CONTINUE, it will continues to run furthur code (read/write) in the core video thread,
- that is to say, if the callback func to nothing and just returns SWITCH_STATUS_CONTINUE, it remains the default behaviour,
- Return SWITCH_STATUS_SUCCESS to skip the default behaviour
- Return SWITCH_STATUS_BREAK will break the loop and end the video thread
-*/
-
-SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_thread_callback(switch_core_session_t *session, switch_core_video_thread_callback_func_t *func, void *user_data);
-
-/*!
- \brief Set a callback to let the core video thread call us
- \param session the session
- \param the current video frame
- \param private user data
- \return SWITCH_STATUS_CONTINUE or SWITCH_STATUS_SUCCESS
-
- If returns SWITCH_STATUS_CONTINUE, it will continues to run furthur code (read/write) in the core video thread,
- that is to say, if the callback func to nothing and just returns SWITCH_STATUS_CONTINUE, it remains the default behaviour,
- Return SWITCH_STATUS_SUCCESS to skip the default behaviour
-*/
-SWITCH_DECLARE(switch_status_t) switch_core_session_video_thread_callback(switch_core_session_t *session, switch_frame_t *frame);
-
SWITCH_DECLARE(switch_hash_index_t *) switch_core_mime_index(void);
SWITCH_DECLARE(const char *) switch_core_mime_ext2type(const char *ext);
SWITCH_DECLARE(const char *) switch_core_mime_type2ext(const char *type);
/* a core_video_thread will be started automatically
when uses rtp based media,
external_video_source should be set to SWITCH_TRUE and
- switch_core_media_start_video_thread()
+ switch_core_session_start_video_thread()
should be explicitly called to start the video thread
if uses the media handle for non-rtp based media
*/
SWITCH_DECLARE(void) switch_core_media_set_stats(switch_core_session_t *session);
SWITCH_DECLARE(void) switch_core_session_wake_video_thread(switch_core_session_t *session);
SWITCH_DECLARE(void) switch_core_session_clear_crypto(switch_core_session_t *session);
-<<<<<<< HEAD
-SWITCH_DECLARE(switch_status_t) switch_core_media_start_video_thread(switch_core_session_t *session);
-=======
-SWITCH_DECLARE(switch_status_t) start_core_video_thread(switch_core_session_t *session);
->>>>>>> allow using the video thread externally - e.g. non rtp based video
SWITCH_DECLARE(switch_status_t) switch_core_session_get_payload_code(switch_core_session_t *session,
switch_media_type_t type,
SWITCH_DECLARE(switch_timer_t *) switch_core_media_get_timer(switch_core_session_t *session, switch_media_type_t mtype);
-
+SWITCH_DECLARE(void) switch_core_media_start_video_function(switch_core_session_t *session, switch_video_function_t video_function, void *user_data);
+SWITCH_DECLARE(void) switch_core_media_end_video_function(switch_core_session_t *session);
+SWITCH_DECLARE(switch_status_t) switch_core_session_start_video_thread(switch_core_session_t *session);
+SWITCH_DECLARE(int) switch_core_media_check_video_function(switch_core_session_t *session);
SWITCH_END_EXTERN_C
#endif
/* For Emacs:
switch_frame_flag_t flags;
void *user_data;
payload_map_t *pmap;
+ switch_image_t *img;
};
SWITCH_END_EXTERN_C
CF_BYPASS_MEDIA_AFTER_HOLD,
CF_HANGUP_HELD,
CF_CONFERENCE_RESET_MEDIA,
+ CF_VIDEO_DECODED_READ,
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
/* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */
CF_FLAG_MAX
SFF_MARKER = (1 << 11),
SFF_WAIT_KEY_FRAME = (1 << 12),
SFF_RAW_RTP_PARSE_FRAME = (1 << 13),
- SFF_PICTURE_RESET = (1 << 14)
+ SFF_PICTURE_RESET = (1 << 14),
+ SFF_SAME_IMAGE = (1 << 15)
} switch_frame_flag_enum_t;
typedef uint32_t switch_frame_flag_t;
typedef switch_bool_t (*switch_tone_detect_callback_t) (switch_core_session_t *, const char *, const char *);
typedef struct switch_xml_binding switch_xml_binding_t;
+typedef void (*switch_video_function_t) (switch_core_session_t *session, void *user_data);
+
typedef switch_status_t (*switch_core_codec_encode_func_t) (switch_codec_t *codec,
switch_codec_t *other_codec,
void *decoded_data,
uint32_t encoded_rate,
void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate, unsigned int *flag);
-typedef switch_status_t (*switch_core_codec_video_encode_func_t) (switch_codec_t *codec,
- switch_image_t *img,
- void *encoded_data, uint32_t *encoded_data_len, unsigned int *flag);
+typedef switch_status_t (*switch_core_codec_video_encode_func_t) (switch_codec_t *codec, switch_frame_t *frame);
-typedef switch_status_t (*switch_core_codec_video_decode_func_t) (switch_codec_t *codec,
- switch_frame_t *frame,
- switch_image_t **img, unsigned int *flag);
+typedef switch_status_t (*switch_core_codec_video_decode_func_t) (switch_codec_t *codec, switch_frame_t *frame);
typedef enum {
SCC_VIDEO_REFRESH = 0
MFLAG_JOIN_ONLY = (1 << 25),
MFLAG_POSITIONAL = (1 << 26),
MFLAG_NO_POSITIONAL = (1 << 27),
- MFLAG_JOIN_VID_FLOOR = (1 << 28),
- MFLAG_RECEIVING_VIDEO = (1 << 29)
+ MFLAG_JOIN_VID_FLOOR = (1 << 28)
} member_flag_t;
typedef enum {
typedef enum {
RFLAG_CAN_SPEAK = (1 << 0),
- RFLAG_CAN_HEAR = (1 << 1),
- RFLAG_CAN_SEND_VIDEO = (1 << 2)
+ RFLAG_CAN_HEAR = (1 << 1)
} relation_flag_t;
typedef enum {
}
- if (member->conference->video_floor_holder && member->conference->video_floor_holder != member && member->channel) {
- // there's already someone hold the floor, tell the core thread start to read video
- switch_channel_clear_flag(member->channel, CF_VIDEO_PASSIVE);
- }
-
unlock_member(member);
switch_mutex_unlock(member->audio_out_mutex);
switch_mutex_unlock(member->audio_in_mutex);
return NULL;
}
-switch_status_t video_thread_callback(switch_core_session_t *session, switch_frame_t *frame, void *user_data)
-{
- switch_channel_t *channel = switch_core_session_get_channel(session);
- char *name = switch_channel_get_name(channel);
- conference_member_t *member = (conference_member_t *)user_data;
- conference_relationship_t *rel = NULL;
-
- if (!member || member->relationships == NULL) return SWITCH_STATUS_SUCCESS;
-
- lock_member(member);
-
- for (rel = member->relationships; rel; rel = rel->next) {
- conference_member_t *imember = conference_member_get(member->conference, rel->id);
- if (imember && switch_test_flag(imember, MFLAG_RECEIVING_VIDEO)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s %d->%d %d\n", name, member->id, imember->id, frame->datalen);
- switch_core_session_write_video_frame(imember->session, frame, SWITCH_IO_FLAG_NONE, 0);
- switch_thread_rwlock_unlock(imember->rwlock);
- }
- }
-
- unlock_member(member);
- return SWITCH_STATUS_SUCCESS;
-}
/* Main video monitor thread (1 per distinct conference room) */
static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thread, void *obj)
}
if (isession && switch_channel_test_flag(ichannel, CF_VIDEO)) {
- if (!switch_test_flag(imember, MFLAG_RECEIVING_VIDEO)) {
- memcpy(vid_frame->packet, buf, vid_frame->packetlen);
- switch_core_session_write_video_frame(imember->session, vid_frame, SWITCH_IO_FLAG_NONE, 0);
- }
+ memcpy(vid_frame->packet, buf, vid_frame->packetlen);
+ switch_core_session_write_video_frame(imember->session, vid_frame, SWITCH_IO_FLAG_NONE, 0);
}
switch_core_session_rwunlock(isession);
static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
- uint8_t nospeak = 0, nohear = 0, sendvideo = 0, clear = 0;
+ uint8_t nospeak = 0, nohear = 0, clear = 0;
switch_assert(conference != NULL);
switch_assert(stream != NULL);
if (member_id > 0 && member->id != member_id) continue;
for (rel = member->relationships; rel; rel = rel->next) {
- stream->write_function(stream, "%d -> %d %s%s%s\n", member->id, rel->id,
+ stream->write_function(stream, "%d -> %d %s%s\n", member->id, rel->id,
(rel->flags & RFLAG_CAN_SPEAK) ? "SPEAK " : "NOSPEAK ",
- (rel->flags & RFLAG_CAN_HEAR) ? "HEAR " : "NOHEAR ",
- (rel->flags & RFLAG_CAN_SEND_VIDEO) ? "SENDVIDEO " : "NOSENDVIDEO ");
+ (rel->flags & RFLAG_CAN_HEAR) ? "HEAR" : "NOHEAR");
}
}
} else {
nospeak = strstr(argv[4], "nospeak") ? 1 : 0;
nohear = strstr(argv[4], "nohear") ? 1 : 0;
- sendvideo = strstr(argv[4], "sendvideo") ? 1 : 0;
if (!strcasecmp(argv[4], "clear")) {
clear = 1;
}
- if (!(clear || nospeak || nohear || sendvideo)) {
+ if (!(clear || nospeak || nohear)) {
return SWITCH_STATUS_GENERR;
}
if (clear) {
- conference_member_t *member = NULL, *other_member = NULL;
+ conference_member_t *member = NULL;
uint32_t id = atoi(argv[2]);
uint32_t oid = atoi(argv[3]);
if ((member = conference_member_get(conference, id))) {
member_del_relationship(member, oid);
- other_member = conference_member_get(conference, oid);
-
- if (other_member) {
- if (switch_test_flag(other_member, MFLAG_RECEIVING_VIDEO)) {
- switch_clear_flag(other_member, MFLAG_RECEIVING_VIDEO);
- if (conference->floor_holder) {
- switch_core_session_refresh_video(conference->floor_holder->session);
- }
- }
- switch_thread_rwlock_unlock(other_member->rwlock);
- }
-
stream->write_function(stream, "relationship %u->%u cleared.\n", id, oid);
switch_thread_rwlock_unlock(member->rwlock);
} else {
return SWITCH_STATUS_SUCCESS;
}
- if (nospeak || nohear || sendvideo) {
+ if (nospeak || nohear) {
conference_member_t *member = NULL, *other_member = NULL;
uint32_t id = atoi(argv[2]);
uint32_t oid = atoi(argv[3]);
if (member && other_member) {
conference_relationship_t *rel = NULL;
- if (sendvideo && switch_test_flag(other_member, MFLAG_RECEIVING_VIDEO) && (! (nospeak || nohear))) {
- stream->write_function(stream, "member %d already receiving video", oid);
- goto skip;
- }
-
if ((rel = member_get_relationship(member, other_member))) {
rel->flags = 0;
} else {
if (nohear) {
switch_clear_flag(rel, RFLAG_CAN_HEAR);
}
- if (sendvideo) {
- switch_set_flag(rel, RFLAG_CAN_SEND_VIDEO);
- switch_set_flag(other_member, MFLAG_RECEIVING_VIDEO);
- switch_core_session_refresh_video(member->session);
- }
-
- stream->write_function(stream, "ok %u->%u %s set\n", id, oid, argv[4]);
+ stream->write_function(stream, "ok %u->%u set\n", id, oid);
} else {
stream->write_function(stream, "error!\n");
}
stream->write_function(stream, "relationship %u->%u not found.\n", id, oid);
}
-skip:
if (member) {
switch_thread_rwlock_unlock(member->rwlock);
}
msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
switch_core_session_receive_message(session, &msg);
- /* Chime in the core video thread */
- switch_core_session_set_video_thread_callback(session, video_thread_callback, (void *)&member);
-
/* Run the conference loop */
do {
conference_loop_output(&member);
} while (member.loop_loop);
- switch_core_session_set_video_thread_callback(session, NULL, NULL);
-
switch_channel_set_private(channel, "_conference_autocall_list_", NULL);
/* Tell the channel we are no longer going to be in a bridge */
if (read_frame) switch_core_session_write_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
{ /* video part */
- uint32_t flag = 0;
uint32_t encoded_data_len = 1500;
switch_frame_t *frame = &vid_frame;
switch_time_t now = switch_micro_time_now() / 1000;
sprintf(ts_str, "%u", timestamp);
text(img->planes[SWITCH_PLANE_PACKED], width, 20, 20, ts_str);
- switch_core_codec_encode_video(codec, img, vid_frame.data, &encoded_data_len, &flag);
+ vid_frame.img = img;
+ switch_core_codec_encode_video(codec, &vid_frame);
while(encoded_data_len) {
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "encoded: %s [%d] flag=%d ts=%lld\n", codec->implementation->iananame, encoded_data_len, flag, last_video_ts);
- frame->datalen = encoded_data_len;
- frame->packetlen = frame->datalen + 12;
- frame->m = flag & SFF_MARKER ? 1 : 0;
frame->timestamp = timestamp;
if (1) { // we can remove this when ts and marker full passed in core
switch_core_session_write_video_frame(session, frame, SWITCH_IO_FLAG_NONE, 0);
- encoded_data_len = 1500;
- switch_core_codec_encode_video(codec, NULL, vid_frame.data, &encoded_data_len, &flag);
+ vid_frame.datalen = 1500;
+ switch_core_codec_encode_video(codec, &vid_frame);
}
}
}
}
if ( 1 ) { /* video part */
- uint32_t flag = 0;
- switch_image_t *img = NULL;
-
- switch_core_codec_decode_video(codec, frame, &img, &flag);
+ switch_core_codec_decode_video(codec, frame);
if ((switch_test_flag(frame, SFF_WAIT_KEY_FRAME))) {
switch_time_t now = switch_micro_time_now();
continue;
}
- if (img) {
- if (img->d_w > 0 && !width) {
- width = img->d_w;
+ if (frame->img) {
+ if (frame->img->d_w > 0 && !width) {
+ width = frame->img->d_w;
switch_channel_set_variable_printf(channel, "video_width", "%d", width);
}
- if (img->d_h > 0 && !height) {
- height = img->d_h;
+ if (frame->img->d_h > 0 && !height) {
+ height = frame->img->d_h;
switch_channel_set_variable_printf(channel, "video_height", "%d", height);
}
decoded_pictures++;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "picture#%d %dx%d\n", decoded_pictures, img->d_w, img->d_h);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "picture#%d %dx%d\n", decoded_pictures, frame->img->d_w, frame->img->d_h);
if (max_pictures && (decoded_pictures >= max_pictures)) {
break;
#include "codec_api.h"
//#include "inc/logging.h" // for debug
-#define FPS 15.0f // frame rate
+#define FPS 20.0f // frame rate
#define H264_NALU_BUFFER_SIZE 65536
#define MAX_NALUS 100
#define SLICE_SIZE 1200 //NALU Slice Size
switch_image_t *img;
int got_sps;
int64_t pts;
+ int need_key_frame;
switch_size_t last_received_timestamp;
switch_bool_t last_received_complete_picture;
} h264_codec_context_t;
int FillSpecificParameters(SEncParamExt& param) {
/* Test for temporal, spatial, SNR scalability */
- param.iPicWidth = 352; // width of picture in samples
- param.iPicHeight = 288; // height of picture in samples
- param.iTargetBitrate = 384000; // target bitrate desired
+ param.iPicWidth = 1280; // width of picture in samples
+ param.iPicHeight = 720; // height of picture in samples
+ param.iTargetBitrate = 1280 * 720 * 8; // target bitrate desired
param.iRCMode = RC_QUALITY_MODE; // rc mode control
param.uiMaxNalSize = SLICE_SIZE * 20;
param.iTemporalLayerNum = 1; // layer number at temporal level
param.bPrefixNalAddingCtrl = 0;
int iIndexLayer = 0;
- param.sSpatialLayers[iIndexLayer].iVideoWidth = 352;
- param.sSpatialLayers[iIndexLayer].iVideoHeight = 288;
- param.sSpatialLayers[iIndexLayer].fFrameRate = 15.0f;
+ param.sSpatialLayers[iIndexLayer].iVideoWidth = 1280;
+ param.sSpatialLayers[iIndexLayer].iVideoHeight = 720;
+ param.sSpatialLayers[iIndexLayer].fFrameRate = (double) (FPS * 1.0f);
// param.sSpatialLayers[iIndexLayer].iQualityLayerNum = 1;
- param.sSpatialLayers[iIndexLayer].iSpatialBitrate = 384000;
+ param.sSpatialLayers[iIndexLayer].iSpatialBitrate = 1280 * 720 * 8;
#ifdef MT_ENABLED
param.sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = SM_DYN_SLICE;
switch_buffer_t *buffer = context->nalu_buffer;
switch_size_t size = 0;
- if (!frame) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No frame in codec!!\n");
- return size;
- }
-
+ switch_assert(frame);
+
nalu_idc = (nalu_hdr & 0x60) >> 5;
nalu_type = nalu_hdr & 0x1f;
if (!context->got_sps && nalu_type != 7) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Waiting SPS/PPS\n");
- switch_set_flag(frame, SFF_WAIT_KEY_FRAME);
- return size;
+ return 0;
}
if (!context->got_sps) context->got_sps = 1;
size = switch_buffer_write(buffer, sync_bytes, sizeof(sync_bytes));
- if (size == 0 ) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Buffer Memory Error!\n");
-
size = switch_buffer_write(buffer, frame->data, frame->datalen);
- if (size == 0 ) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Buffer Memory Error!\n");
+
#ifdef DEBUG_H264
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "ts: %ld len: %4d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x mark=%d size=%d\n",
return size;
}
-static switch_status_t nalu_slice(h264_codec_context_t *context, void *data, uint32_t *len, uint32_t *flag)
+static switch_status_t nalu_slice(h264_codec_context_t *context, switch_frame_t *frame)
{
int nalu_len;
uint8_t *buffer;
switch_status_t status = SWITCH_STATUS_SUCCESS;
- *flag &= ~SFF_MARKER;
+ frame->m = SWITCH_FALSE;
if (context->cur_nalu_index >= context->bit_stream_info.sLayerInfo[context->cur_layer].iNalCount) {
context->cur_nalu_index = 0;
if (context->last_frame_type == videoFrameTypeSkip ||
context->cur_layer >= context->bit_stream_info.iLayerNum) {
- *len = 0;
- *flag |= SFF_MARKER;
+ frame->datalen = 0;
+ frame->m = SWITCH_TRUE;
context->cur_layer = 0;
context->cur_nalu_index = 0;
return status;
// if (nalu_type == 7) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Got SPS\n");
- memcpy(data, (buffer + context->last_nalu_data_pos), nalu_len);
- *len = nalu_len;
+ memcpy(frame->data, (buffer + context->last_nalu_data_pos), nalu_len);
+ frame->datalen = nalu_len;
// *flag |= (nalu_type == 6 || nalu_type == 7 || nalu_type == 8 || (nalu_type == 0xe && context->last_nalu_type == 8)) ? 0 : SFF_MARKER;
if ((context->cur_nalu_index == context->bit_stream_info.sLayerInfo[context->cur_layer].iNalCount - 1) &&
(context->cur_layer == context->bit_stream_info.iLayerNum - 1)) {
- *flag |= SFF_MARKER;
+ frame->m = SWITCH_TRUE;
} else {
status = SWITCH_STATUS_MORE_DATA;
}
goto end;
} else {
int left = nalu_len;
- uint8_t *p = (uint8_t *)data;
+ uint8_t *p = (uint8_t *) frame->data;
if (context->nalu_eat) {
left = nalu_len + 4 - context->nalu_eat;
memcpy(p + 2, buffer + context->last_nalu_data_pos, SLICE_SIZE - 2);
context->last_nalu_data_pos += (SLICE_SIZE - 2);
context->nalu_eat += (SLICE_SIZE - 2);
- *len = SLICE_SIZE;
+ frame->datalen = SLICE_SIZE;
status = SWITCH_STATUS_MORE_DATA;
goto end;
} else {
p[1] = 0x40 | context->last_nalu_type;
memcpy(p + 2, buffer + context->last_nalu_data_pos, left);
context->last_nalu_data_pos += left;
- *len = left + 2;
- *flag |= SFF_MARKER;
+ frame->datalen = left + 2;
+ frame->m = SWITCH_TRUE;
context->nalu_eat = 0;
context->cur_nalu_index++;
status = SWITCH_STATUS_MORE_DATA;
context->encoder_params.iPicWidth = width;
context->encoder_params.iPicHeight = height;
+
for (int i=0; i<context->encoder_params.iSpatialLayerNum; i++) {
context->encoder_params.sSpatialLayers[i].iVideoWidth = width;
context->encoder_params.sSpatialLayers[i].iVideoHeight = height;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder Init Error\n");
return SWITCH_STATUS_FALSE;
}
+
context->encoder_initialized = SWITCH_TRUE;
return SWITCH_STATUS_SUCCESS;
}
-static switch_status_t switch_h264_encode(switch_codec_t *codec,
- switch_image_t *img,
- void *encoded_data, uint32_t *encoded_data_len,
- unsigned int *flag)
+static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t *frame)
{
h264_codec_context_t *context = (h264_codec_context_t *)codec->private_info;
int width = 0;
SSourcePicture* pic = NULL;
long result;
- if (*flag & SFF_WAIT_KEY_FRAME) {
+ if (context->need_key_frame) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "H264 KEYFRAME GENERATED\n");
context->encoder->ForceIntraFrame(1);
+ context->need_key_frame = 0;
}
- if (img == NULL) {
- return nalu_slice(context, encoded_data, encoded_data_len, flag);
+ if (frame->flags & SFF_SAME_IMAGE) {
+ return nalu_slice(context, frame);
}
- //d_w and d_h are corrupt
- width = img->w;
- height = img->h;
+
+ if (frame->img->d_h > 1) {
+ width = frame->img->d_w;
+ height = frame->img->d_h;
+ } else {
+ width = frame->img->w;
+ height = frame->img->h;
+ }
//switch_assert(width > 0 && (width % 2 == 0));
//switch_assert(height > 0 && (height % 2 == 0));
pic->iColorFormat = videoFormatI420;
pic->iPicHeight = height;
pic->iPicWidth = width;
- pic->iStride[0] = img->stride[0];
- pic->iStride[1] = img->stride[1]; // = img->stride[2];
+ pic->iStride[0] = frame->img->stride[0];
+ pic->iStride[1] = frame->img->stride[1]; // = frame->img->stride[2];
- pic->pData[0] = img->planes[0];
- pic->pData[1] = img->planes[1];
- pic->pData[2] = img->planes[2];
+ pic->pData[0] = frame->img->planes[0];
+ pic->pData[1] = frame->img->planes[1];
+ pic->pData[2] = frame->img->planes[2];
result = (EVideoFrameType)context->encoder->EncodeFrame(pic, &context->bit_stream_info);
if (result != cmResultSuccess ) {
context->cur_nalu_index = 0;
context->last_nalu_data_pos = 0;
- if(pic){
+ if (pic){
delete pic;
pic = NULL;
}
- return nalu_slice(context, encoded_data, encoded_data_len, flag);
+
+ return nalu_slice(context, frame);
error:
+
if(pic){
delete pic;
pic = NULL;
}
- *encoded_data_len = 0;
- *flag |= SFF_MARKER;
+ frame->datalen = 0;
+ frame->m = SWITCH_TRUE;
+
return SWITCH_STATUS_FALSE;
}
-static switch_status_t switch_h264_decode(switch_codec_t *codec,
- switch_frame_t *frame,
- switch_image_t **img,
- unsigned int *flag)
+static switch_status_t switch_h264_decode(switch_codec_t *codec, switch_frame_t *frame)
{
h264_codec_context_t *context = (h264_codec_context_t *)codec->private_info;
switch_size_t size = 0;
uint32_t error_code;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "len: %d ts: %u mark:%d\n", frame->datalen, ntohl(frame->timestamp), frame->m);
- if (context->last_received_timestamp && context->last_received_timestamp != frame->timestamp &&
+ if (0 && context->last_received_timestamp && context->last_received_timestamp != frame->timestamp &&
(!frame->m) && (!context->last_received_complete_picture)) {
// possible packet loss
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Packet Loss, skip privousely received packets\n");
- switch_buffer_zero(context->nalu_buffer);
+ switch_goto_status(SWITCH_STATUS_RESTART, end);
}
context->last_received_timestamp = frame->timestamp;
context->last_received_complete_picture = frame->m ? SWITCH_TRUE : SWITCH_FALSE;
size = buffer_h264_nalu(context, frame);
+ printf("READ buf:%ld got_key:%d st:%d m:%d\n", size, context->got_sps, status, frame->m);
+
if (frame->m && size) {
int got_picture = 0;
SBufferInfo dest_buffer_info;
switch_buffer_peek_zerocopy(context->nalu_buffer, &nalu);
uint8_t* pData[3] = { 0 };
+
+
+ frame->m = SWITCH_FALSE;
+ frame->flags = 0;
+
pData[0] = NULL;
pData[1] = NULL;
context->img->stride[1] = dest_buffer_info.UsrData.sSystemBuffer.iStride[1];
context->img->stride[2] = dest_buffer_info.UsrData.sSystemBuffer.iStride[1];
- *img = context->img;
+ frame->img = context->img;
// TODO: keep going and see if more picture available
// pDecoder->DecodeFrame (NULL, 0, pData, &sDstBufInfo);
} else {
if (error_code) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decode error: 0x%x\n", error_code);
- context->got_sps = 0;
+ switch_goto_status(SWITCH_STATUS_RESTART, end);
}
}
switch_buffer_zero(context->nalu_buffer);
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
}
end:
- return SWITCH_STATUS_SUCCESS;
+
+ if (size == 0) {
+ status == SWITCH_STATUS_MORE_DATA;
+ }
+
+ if (status == SWITCH_STATUS_RESTART) {
+ context->got_sps = 0;
+ switch_buffer_zero(context->nalu_buffer);
+ }
+
+ if (!context->got_sps) {
+ switch_set_flag(frame, SFF_WAIT_KEY_FRAME);
+ }
+
+ if (!frame->img) {
+ status = SWITCH_STATUS_MORE_DATA;
+ }
+
+ return status;
}
static switch_status_t switch_h264_control(switch_codec_t *codec,
switch_codec_control_type_t *rtype,
void **ret_data) {
+
+
+ h264_codec_context_t *context = (h264_codec_context_t *)codec->private_info;
+
+ switch(cmd) {
+ case SCC_VIDEO_REFRESH:
+ context->need_key_frame = 1;
+ break;
+ default:
+ break;
+ }
+
return SWITCH_STATUS_SUCCESS;
}
#include <vpx/vp8dx.h>
#include <vpx/vp8.h>
-#define FPS 15
+#define FPS 20
#define SLICE_SIZE 1200
SWITCH_MODULE_LOAD_FUNCTION(mod_vpx_load);
vpx_context_t *context = (vpx_context_t *)codec->private_info;
vpx_codec_enc_cfg_t *config = &context->config;
+ if (!context->codec_settings.video.width) {
+ context->codec_settings.video.width = 1280;
+ }
+
+ if (!context->codec_settings.video.height) {
+ context->codec_settings.video.height = 720;
+ }
+
+ if (context->codec_settings.video.bandwidth) {
+ context->bandwidth = context->codec_settings.video.bandwidth;
+ } else {
+ context->bandwidth = context->codec_settings.video.width * context->codec_settings.video.height * 8;
+ }
+
+ if (context->bandwidth > 1250000) {
+ context->bandwidth = 1250000;
+ }
+
// settings
config->g_profile = 1;
config->g_w = context->codec_settings.video.width;
config->g_timebase.den = 1000;
config->g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS;
config->g_lag_in_frames = 0; // 0- no frame lagging
- config->g_threads = 1;
+ config->g_threads = (switch_core_cpu_count() > 1) ? 2 : 1;
+
// rate control settings
config->rc_dropframe_thresh = 0;
config->rc_end_usage = VPX_CBR;
vpx_codec_control(&context->decoder, VP8_SET_POSTPROC, &ppcfg);
switch_buffer_create_dynamic(&context->vpx_packet_buffer, 512, 512, 1024000);
+
+ printf("WTF CREATE ??? %p\n", (void *)context->vpx_packet_buffer);
}
return SWITCH_STATUS_SUCCESS;
+-+-+-+-+-+-+-+-+
*/
-static switch_status_t consume_partition(vpx_context_t *context, void *data, uint32_t *len, uint32_t *flag)
+static switch_status_t consume_partition(vpx_context_t *context, switch_frame_t *frame)
{
if (!context->pkt) context->pkt = vpx_codec_get_cx_data(&context->encoder, &context->iter);
- *flag &= ~SFF_MARKER;
+ frame->m = 0;
if (context->pkt) {
// if (context->pkt->kind == VPX_CODEC_CX_FRAME_PKT && (context->pkt->data.frame.flags & VPX_FRAME_IS_KEY) && context->pkt_pos == 0) {
}
if (!context->pkt || context->pkt_pos >= context->pkt->data.frame.sz - 1 || context->pkt->kind != VPX_CODEC_CX_FRAME_PKT) {
- *len = 0;
- *flag |= SFF_MARKER;
+ frame->datalen = 0;
+ frame->m = 1;
context->pkt_pos = 0;
context->pkt = NULL;
return SWITCH_STATUS_SUCCESS;
if (context->pkt->data.frame.sz < SLICE_SIZE) {
uint8_t hdr = 0x10;
- memcpy(data, &hdr, 1);
- memcpy((uint8_t *)data + 1, context->pkt->data.frame.buf, context->pkt->data.frame.sz);
- *len = context->pkt->data.frame.sz + 1;
- *flag |= SFF_MARKER;
+ memcpy(frame->data, &hdr, 1);
+ memcpy((uint8_t *)frame->data + 1, context->pkt->data.frame.buf, context->pkt->data.frame.sz);
+ frame->datalen = context->pkt->data.frame.sz + 1;
+ frame->m = 1;
context->pkt = NULL;
context->pkt_pos = 0;
return SWITCH_STATUS_SUCCESS;
} else {
int left = context->pkt->data.frame.sz - context->pkt_pos;
- uint8_t *p = data;
+ uint8_t *p = frame->data;
if (left < SLICE_SIZE) {
p[0] = 0;
memcpy(p+1, (uint8_t *)context->pkt->data.frame.buf + context->pkt_pos, left);
context->pkt_pos = 0;
context->pkt = NULL;
- *len = left + 1;
- *flag |= SFF_MARKER;
+ frame->datalen = left + 1;
+ frame->m = 1;
return SWITCH_STATUS_SUCCESS;
} else {
uint8_t hdr = context->pkt_pos == 0 ? 0x10 : 0;
p[0] = hdr;
memcpy(p+1, (uint8_t *)context->pkt->data.frame.buf + context->pkt_pos, SLICE_SIZE - 1);
context->pkt_pos += (SLICE_SIZE - 1);
- *len = SLICE_SIZE;
+ frame->datalen = SLICE_SIZE;
return SWITCH_STATUS_MORE_DATA;
}
}
}
-static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_image_t *img,
- void *encoded_data, uint32_t *encoded_data_len,
- unsigned int *flag)
+static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *frame)
{
vpx_context_t *context = (vpx_context_t *)codec->private_info;
uint32_t duration = 90000 / FPS;
int height = 0;
vpx_enc_frame_flags_t vpx_flags = 0;
- if (*flag & SFF_WAIT_KEY_FRAME) {
- context->need_key_frame = 1;
- }
- if (img == NULL) {
- return consume_partition(context, encoded_data, encoded_data_len, flag);
+ if (frame->flags & SFF_SAME_IMAGE) {
+ return consume_partition(context, frame);
}
//d_w and d_h are messed up
+ //printf("WTF %d %d\n", frame->img->d_w, frame->img->d_h);
- //printf("WTF %d %d\n", img->d_w, img->d_h);
-
- width = img->w;
- height = img->h;
+ if (frame->img->d_h > 1) {
+ width = frame->img->d_w;
+ height = frame->img->d_h;
+ } else {
+ width = frame->img->w;
+ height = frame->img->h;
+ }
//switch_assert(width > 0 && (width % 4 == 0));
//switch_assert(height > 0 && (height % 4 == 0));
if (context->config.g_w != width || context->config.g_h != height) {
context->codec_settings.video.width = width;
context->codec_settings.video.height = height;
- if (context->codec_settings.video.bandwidth) {
- context->bandwidth = context->codec_settings.video.bandwidth;
- } else {
- context->bandwidth = width * height * 8;
- }
-
- if (context->bandwidth > 1250000) {
- context->bandwidth = 1250000;
- }
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_NOTICE,
"VPX reset encoder picture from %dx%d to %dx%d %u BW\n",
context->config.g_w, context->config.g_h, width, height, context->bandwidth);
init_codec(codec);
- *flag |= SFF_PICTURE_RESET;
+ frame->flags |= SFF_PICTURE_RESET;
context->need_key_frame = 1;
}
- if (context->need_key_frame > 0) {
+
+ if (!context->encoder_init) {
+ init_codec(codec);
+ }
+
+ if (context->need_key_frame != 0) {
// force generate a key frame
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VPX KEYFRAME REQ\n");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VPX KEYFRAME GENERATED\n");
vpx_flags |= VPX_EFLAG_FORCE_KF;
- context->need_key_frame--;
+ context->need_key_frame = 0;
}
- if (vpx_codec_encode(&context->encoder, (vpx_image_t *)img, context->pts, duration, vpx_flags, VPX_DL_REALTIME) != VPX_CODEC_OK) {
+ if (vpx_codec_encode(&context->encoder, (vpx_image_t *) frame->img, context->pts, duration, vpx_flags, VPX_DL_REALTIME) != VPX_CODEC_OK) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VP8 encode error %d:%s\n",
context->encoder.err, context->encoder.err_detail);
+
+ frame->datalen = 0;
return SWITCH_STATUS_FALSE;
}
context->pts += duration;
context->iter = NULL;
- return consume_partition(context, encoded_data, encoded_data_len, flag);
+ return consume_partition(context, frame);
}
-static void buffer_vpx_packets(vpx_context_t *context, switch_frame_t *frame)
+static switch_status_t buffer_vpx_packets(vpx_context_t *context, switch_frame_t *frame)
{
uint8_t *data = frame->data;
uint8_t S;
if (!frame) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no frame in codec!!\n");
- return;
+ return SWITCH_STATUS_RESTART;
}
DES = *data;
}
len = frame->datalen - (data - (uint8_t *)frame->data);
+
if (len <= 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid packet %d\n", len);
- switch_buffer_zero(context->vpx_packet_buffer);
- return;
+ return SWITCH_STATUS_RESTART;
}
-
+
if (S && (PID == 0)) {
- uint8_t keyframe;
+ int is_keyframe = ((*data) & 0x01) ? 0 : 1;
- keyframe = ((*data) & 0x01) ? 0 : 1;
-
- // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[%d] PID: %d K:%d P:%d Inv:%d len: %d size:%d\n", frame->datalen, PID, keyframe, profile, invisible, len, size);
-
- if (keyframe) {
- if (!context->got_key_frame) context->got_key_frame = 1;
+ if (is_keyframe && !context->got_key_frame) {
+ context->got_key_frame = 1;
}
}
if (!context->got_key_frame) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Waiting for key frame\n");
- switch_set_flag(frame, SFF_WAIT_KEY_FRAME);
- return;
+ return SWITCH_STATUS_RESTART;
}
switch_buffer_write(context->vpx_packet_buffer, data, len);
+
+ return SWITCH_STATUS_SUCCESS;
+
}
-static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *frame, switch_image_t **img, unsigned int *flag)
+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;
- vpx_codec_ctx_t *decoder = &context->decoder;
switch_size_t len;
+ vpx_codec_ctx_t *decoder = NULL;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+ if (!context->decoder_init) {
+ init_codec(codec);
+ }
- if (!decoder) {
+ 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: %" SWITCH_SIZE_T_FMT " mark:%d\n", frame->datalen, frame->timestamp, frame->m);
- if (context->last_received_timestamp && context->last_received_timestamp != frame->timestamp &&
+ if (context->last_received_timestamp && context->last_received_timestamp != frame->timestamp &&
(!frame->m) && (!context->last_received_complete_picture)) {
// possible packet loss
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Packet Loss, skip previouse received frame (to avoid crash?)\n");
- switch_buffer_zero(context->vpx_packet_buffer);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Packet Loss, skip previous received frame (to avoid crash?)\n");
+ switch_goto_status(SWITCH_STATUS_RESTART, end);
}
context->last_received_timestamp = frame->timestamp;
context->last_received_complete_picture = frame->m ? SWITCH_TRUE : SWITCH_FALSE;
- buffer_vpx_packets(context, frame);
+ status = buffer_vpx_packets(context, frame);
- len = switch_buffer_inuse(context->vpx_packet_buffer);
+ 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);
- if (frame->m && len) {
+ if (status == SWITCH_STATUS_SUCCESS && frame->m && (len = switch_buffer_inuse(context->vpx_packet_buffer))) {
uint8_t *data;
vpx_codec_iter_t iter = NULL;
int corrupted = 0;
int err;
- // int keyframe = 0;
+ //int keyframe = 0;
+
+ printf("WTF %d %ld\n", frame->m, len);
switch_buffer_peek_zerocopy(context->vpx_packet_buffer, (void *)&data);
- // keyframe = (*data & 0x01) ? 0 : 1;
+ //keyframe = (*data & 0x01) ? 0 : 1;
- // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buffered: %" SWITCH_SIZE_T_FMT ", key: %d\n", len, keyframe);
+ //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buffered: %" SWITCH_SIZE_T_FMT ", key: %d\n", len, keyframe);
err = vpx_codec_decode(decoder, data, (unsigned int)len, NULL, 0);
if (err != VPX_CODEC_OK) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error decoding %" SWITCH_SIZE_T_FMT " bytes, [%d:%d:%s]\n", len, err, decoder->err, decoder->err_detail);
- switch_set_flag(frame, SFF_WAIT_KEY_FRAME);
- context->got_key_frame = 0;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "require key frame %d\n", context->got_key_frame);
- goto error;
+ 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");
- goto error;
+ switch_goto_status(SWITCH_STATUS_RESTART, end);
}
- *img = (switch_image_t *)vpx_codec_get_frame(decoder, &iter);
+ frame->img = (switch_image_t *) vpx_codec_get_frame(decoder, &iter);
- if (!(*img) || corrupted) {
+ if (!(frame->img) || corrupted) {
switch_buffer_zero(context->vpx_packet_buffer);
- goto ok;
+ switch_goto_status(SWITCH_STATUS_SUCCESS, end);
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%dx%d %dx%d\n", (*img)->w,(*img)->h, (*img)->d_w, (*img)->d_h);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%dx%d %dx%d\n", frame->img->w,frame->img->h, frame->img->d_w, frame->img->d_h);
switch_buffer_zero(context->vpx_packet_buffer);
}
-ok:
- return SWITCH_STATUS_SUCCESS;
+end:
+
+ if (status == SWITCH_STATUS_RESTART) {
+ context->got_key_frame = 0;
+ switch_buffer_zero(context->vpx_packet_buffer);
+ }
+
+ if (!frame->img) {
+ status = SWITCH_STATUS_MORE_DATA;
+ }
-error:
- switch_buffer_zero(context->vpx_packet_buffer);
+ if (!context->got_key_frame) {
+ switch_set_flag(frame, SFF_WAIT_KEY_FRAME);
+ }
- return SWITCH_STATUS_FALSE;
+ return status;
}
}
}
-static switch_status_t switch_yuv_encode(switch_codec_t *codec,
- switch_image_t *img,
- void *encoded_data, uint32_t *encoded_data_len,
- unsigned int *flag)
+static switch_status_t switch_yuv_encode(switch_codec_t *codec, switch_frame_t *frame)
{
/* yuv encode is unclear, so return 0 for now */
- *encoded_data_len = 0;
- *flag |= SFF_MARKER;
+ frame->datalen = 0;
+ frame->m = 1;
return SWITCH_STATUS_SUCCESS;
}
-static switch_status_t switch_yuv_decode(switch_codec_t *codec,
- switch_frame_t *frame,
- switch_image_t **img,
- unsigned int *flag)
+static switch_status_t switch_yuv_decode(switch_codec_t *codec, switch_frame_t *frame)
{
switch_assert(frame);
- *img = (switch_image_t *)frame->user_data;
+ frame->img = (switch_image_t *)frame->user_data;
return SWITCH_STATUS_SUCCESS;
}
int height;
int force_width;
int force_height;
- int video_refresh_req;
int channels;
};
switch_assert(context->img);
yuyv_to_i420(*p_pixels, context->img->img_data, context->width, context->height);
+
switch_mutex_unlock(context->video_mutex);
}
{
vlc_video_context_t *context = (vlc_video_context_t *)data;
-
switch_assert(id == NULL); /* picture identifier, not needed here */
if (context->channel && !switch_channel_test_flag(context->channel, CF_VIDEO)) return;
- if (!context->img) context->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, context->width, context->height, 0);
- switch_assert(context->img);
-
+ if (!context->img) context->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, context->width, context->height, 0); switch_assert(context->img);
+
yuyv_to_i420(*p_pixels, context->img->img_data, context->width, context->height);
switch_mutex_unlock(context->video_mutex);
static void vlc_video_display_callback(void *data, void *id)
{
- vlc_video_context_t *context = (vlc_video_context_t *) data;
- int32_t flag = 0;
-
/* VLC wants to display the video */
+ vlc_video_context_t *context = (vlc_video_context_t *) data;
+
if (context->channel && !switch_channel_test_flag(context->channel, CF_VIDEO)) return;
- if (context->video_refresh_req > 0) {
- flag |= SFF_WAIT_KEY_FRAME;
- context->video_refresh_req--;
- }
+ context->vid_frame->img = context->img;
- switch_core_session_write_video_image(context->session, context->vid_frame, context->img, SWITCH_DEFAULT_VIDEO_SIZE, NULL);
+ switch_core_session_write_video_frame(context->session, context->vid_frame, SWITCH_IO_FLAG_NONE, 0);
}
unsigned video_format_setup_callback(void **opaque, char *chroma, unsigned *width, unsigned *height, unsigned *pitches, unsigned *lines)
frame_size = (*width) * (*height) * 4 * 2;
context->raw_yuyv_data = malloc(frame_size);
+
if (context->raw_yuyv_data == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "memory error\n");
return 0;
goto fail;
}
- start_core_video_thread(*new_session);
+ switch_core_session_start_video_thread(*new_session);
switch_channel_set_state(channel, CS_INIT);
if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) {
case SWITCH_MESSAGE_INDICATE_JITTER_BUFFER:
break;
case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
- tech_pvt->context->video_refresh_req = 1;
+ switch_core_media_gen_key_frame(session);
break;
default:
break;
return status;
}
-SWITCH_DECLARE(switch_status_t) switch_core_codec_encode_video(switch_codec_t *codec,
- switch_image_t *img,
- void *encoded_data, uint32_t *encoded_data_len, unsigned int *flag)
+SWITCH_DECLARE(switch_status_t) switch_core_codec_encode_video(switch_codec_t *codec, switch_frame_t *frame)
{
switch_status_t status = SWITCH_STATUS_FALSE;
if (codec->mutex) switch_mutex_lock(codec->mutex);
if (codec->implementation->encode_video) {
- status = codec->implementation->encode_video(codec, img, encoded_data, encoded_data_len, flag);
+ status = codec->implementation->encode_video(codec, frame);
+
+ if (frame->datalen) {
+ frame->packetlen = frame->datalen + 12;
+ frame->flags |= SFF_SAME_IMAGE;
+ } else {
+ frame->flags &= ~SFF_SAME_IMAGE;
+ }
}
if (codec->mutex) switch_mutex_unlock(codec->mutex);
}
-SWITCH_DECLARE(switch_status_t) switch_core_codec_decode_video(switch_codec_t *codec,
- switch_frame_t *frame,
- switch_image_t **img, unsigned int *flag)
+SWITCH_DECLARE(switch_status_t) switch_core_codec_decode_video(switch_codec_t *codec, switch_frame_t *frame)
{
switch_status_t status = SWITCH_STATUS_FALSE;
if (codec->mutex) switch_mutex_lock(codec->mutex);
if (codec->implementation->decode_video) {
- status = codec->implementation->decode_video(codec, frame, img, flag);
+ status = codec->implementation->decode_video(codec, frame);
}
if (codec->mutex) switch_mutex_unlock(codec->mutex);
switch_mutex_t *mutex;
switch_mutex_t *sdp_mutex;
+ switch_mutex_t *control_mutex;
const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS];
int num_negotiated_codecs;
switch_time_t video_last_key_time;
switch_time_t video_init;
switch_timer_t video_timer;
+ switch_video_function_t video_function;
+ void *video_user_data;
+ int8_t video_function_running;
};
session->media_handle->mparams = params;
if (!session->media_handle->mparams->video_key_freq) {
- session->media_handle->mparams->video_key_freq = 15000000;
+ session->media_handle->mparams->video_key_freq = 30000000;
}
if (!session->media_handle->mparams->video_key_first) {
switch_mutex_init(&session->media_handle->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
switch_mutex_init(&session->media_handle->sdp_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+ switch_mutex_init(&session->media_handle->control_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO].ssrc =
(uint32_t) ((intptr_t) &session->media_handle->engines[SWITCH_MEDIA_TYPE_AUDIO] + (uint32_t) time(NULL));
engine = &smh->engines[type];
- engine->read_frame.datalen = 0;
-
if (!engine->read_codec.implementation || !switch_core_codec_ready(&engine->read_codec)) {
return SWITCH_STATUS_FALSE;
}
switch_assert(engine->rtp_session != NULL);
- engine->read_frame.datalen = 0;
+
if (!switch_channel_up_nosig(session->channel) || !switch_rtp_ready(engine->rtp_session) || switch_channel_test_flag(session->channel, CF_NOT_READY)) {
return SWITCH_STATUS_FALSE;
return SWITCH_STATUS_INUSE;
}
-
+
+ engine->read_frame.datalen = 0;
+ engine->read_frame.flags = SFF_NONE;
+ engine->read_frame.m = SWITCH_FALSE;
+ engine->read_frame.img = NULL;
+
while (smh->media_flags[SCMF_RUNNING] && engine->read_frame.datalen == 0) {
engine->read_frame.flags = SFF_NONE;
continue;
}
+ if (smh->video_function) {
+ int run = 0;
+
+ switch_mutex_lock(smh->control_mutex);
+ if (smh->video_function_running == 0) {
+ smh->video_function_running = 1;
+ run = 1;
+ }
+ switch_mutex_unlock(smh->control_mutex);
+
+ if (run) {
+ smh->video_function(session, smh->video_user_data);
+ switch_mutex_lock(smh->control_mutex);
+ smh->video_function = NULL;
+ smh->video_user_data = NULL;
+ smh->video_function_running = 0;
+ switch_mutex_unlock(smh->control_mutex);
+ }
+ }
status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0);
switch_cond_next();
continue;
}
-
if (switch_channel_test_flag(channel, CF_VIDEO_REFRESH_REQ)) {
switch_core_session_refresh_video(session);
continue;
}
- status = switch_core_session_video_thread_callback(session, read_frame);
-
- if (status != SWITCH_STATUS_CONTINUE) {
- if (status == SWITCH_STATUS_SUCCESS) continue;
-
- break;
- }
-
if (switch_channel_test_flag(channel, CF_VIDEO_ECHO)) {
switch_core_session_write_video_frame(session, read_frame, SWITCH_IO_FLAG_NONE, 0);
}
return NULL;
}
-
-SWITCH_DECLARE(switch_status_t) switch_core_media_start_video_thread(switch_core_session_t *session)
+SWITCH_DECLARE(switch_status_t) switch_core_session_start_video_thread(switch_core_session_t *session)
{
switch_threadattr_t *thd_attr = NULL;
switch_memory_pool_t *pool = switch_core_session_get_pool(session);
return SWITCH_STATUS_SUCCESS;
}
+SWITCH_DECLARE(void) switch_core_media_start_video_function(switch_core_session_t *session, switch_video_function_t video_function, void *user_data)
+{
+ switch_media_handle_t *smh;
+
+ if (!(smh = session->media_handle)) {
+ return;
+ }
+
+ switch_mutex_lock(smh->control_mutex);
+ if (!smh->video_function_running) {
+ smh->video_function = video_function;
+ smh->video_user_data = user_data;
+ switch_core_session_video_reset(session);
+ switch_core_session_start_video_thread(session);
+ }
+ switch_mutex_unlock(smh->control_mutex);
+}
+
+SWITCH_DECLARE(int) switch_core_media_check_video_function(switch_core_session_t *session)
+{
+ switch_media_handle_t *smh;
+ int r;
+
+ if (!(smh = session->media_handle)) {
+ return 0;
+ }
+
+ switch_mutex_lock(smh->control_mutex);
+ r = (smh->video_function_running > 0);
+ switch_mutex_unlock(smh->control_mutex);
+
+ return r;
+}
+
+SWITCH_DECLARE(void) switch_core_media_end_video_function(switch_core_session_t *session)
+{
+ switch_media_handle_t *smh;
+
+ if (!(smh = session->media_handle)) {
+ return;
+ }
+
+ switch_mutex_lock(smh->control_mutex);
+ if (smh->video_function_running > 0) {
+ smh->video_function_running = -1;
+ }
+ switch_mutex_unlock(smh->control_mutex);
+
+ while(smh->video_function_running != 0) {
+ switch_yield(10000);
+ }
+}
+
+
+>>>>>>> another refactoring pass, temp code still in place, WORK IN PROGRESS
//?
#define RA_PTR_LEN 512
SWITCH_DECLARE(switch_status_t) switch_core_media_proxy_remote_addr(switch_core_session_t *session, const char *sdp_str)
!switch_channel_test_flag(session->channel, CF_WEBRTC)) {
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
- switch_core_media_start_video_thread(session);
-
+ switch_core_session_start_video_thread(session);
}
if (switch_media_handle_test_media_flag(smh, SCMF_AUTOFIX_TIMING)) {
v_engine->check_frames = 0;
v_engine->local_sdp_ip, v_engine->local_sdp_port, v_engine->cur_payload_map->remote_sdp_ip,
v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt);
-
- switch_core_media_start_video_thread(session);
+ switch_core_session_start_video_thread(session);
switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt);
}
}
!((val = switch_channel_get_variable(session->channel, "disable_rtp_auto_adjust")) && switch_true(val))) {
/* Reactivate the NAT buster flag. */
switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
- switch_core_media_start_video_thread(session);
+ switch_core_session_start_video_thread(session);
}
}
}
switch_rtp_set_payload_map(v_engine->rtp_session, &v_engine->payload_map);
-
- switch_core_media_start_video_thread(session);
+ switch_core_session_start_video_thread(session);
switch_channel_set_flag(session->channel, CF_VIDEO);
if ((ssrc = switch_channel_get_variable(session->channel, "rtp_use_video_ssrc"))) {
case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
{
if (v_engine->rtp_session) {
- switch_rtp_video_refresh(v_engine->rtp_session);
+ if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_FIR)) {
+ switch_rtp_video_refresh(v_engine->rtp_session);
+ } else if (switch_rtp_test_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PLI)) {
+ switch_rtp_video_loss(v_engine->rtp_session);
+ }
}
}
session->image_write_callback_user_data = user_data;
}
-SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_image(switch_core_session_t *session, switch_frame_t *frame,
- switch_image_t *img, switch_size_t size, uint32_t *flag)
+static switch_status_t raw_write_video(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
{
- uint32_t encoded_data_len = size, lflag = 0, *flagp = flag;
- switch_codec_t *codec = switch_core_session_get_video_write_codec(session);
- switch_timer_t *timer;
- switch_media_handle_t *smh;
- //switch_rtp_engine_t *v_engine;
-
- switch_assert(session);
-
- if (!(smh = session->media_handle)) {
- return SWITCH_STATUS_FALSE;
- }
-
- //v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO];
-
-
- if (!flag) {
- flagp = &lflag;
- }
-
- if (!(timer = switch_core_media_get_timer(session, SWITCH_MEDIA_TYPE_VIDEO))) {
+ switch_io_event_hook_video_write_frame_t *ptr;
+ switch_status_t status = SWITCH_STATUS_FALSE;
- if (!smh->video_timer.timer_interface) {
- switch_core_timer_init(&smh->video_timer, "soft", 1, 90, switch_core_session_get_pool(session));
+ if (session->endpoint_interface->io_routines->write_video_frame) {
+ if ((status = session->endpoint_interface->io_routines->write_video_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {
+ for (ptr = session->event_hooks.video_write_frame; ptr; ptr = ptr->next) {
+ if ((status = ptr->video_write_frame(session, frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
+ break;
+ }
+ }
}
-
- timer = &smh->video_timer;
}
-
- do {
- encoded_data_len = size;
- switch_core_codec_encode_video(codec, img, frame->data, &encoded_data_len, flagp);
-
- if (*flagp & SFF_PICTURE_RESET) {
- smh->video_init = 0;
- smh->video_last_key_time = 0;
- *flagp &= ~SFF_PICTURE_RESET;
- }
-
- frame->datalen = encoded_data_len;
- frame->packetlen = frame->datalen + 12;
- frame->m = (*flagp & SFF_MARKER) ? 1 : 0;
- frame->timestamp = timer->samplecount;
-
- switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME);
-
- switch_core_session_write_video_frame(session, frame, SWITCH_IO_FLAG_NONE, 0);
-
- if (session->image_write_callback) {
- session->image_write_callback(session, frame, img, session->image_write_callback_user_data);
- }
-
- img = NULL;
-
- } while(encoded_data_len);
-
- return SWITCH_STATUS_SUCCESS;
+ return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags,
int stream_id)
{
- switch_io_event_hook_video_write_frame_t *ptr;
switch_status_t status = SWITCH_STATUS_FALSE;
- switch_media_handle_t *smh;
-
switch_time_t now = switch_micro_time_now();
+ switch_codec_t *codec = switch_core_session_get_video_write_codec(session);
+ switch_timer_t *timer;
+ switch_media_handle_t *smh;
+ switch_image_t *img = frame->img;
switch_assert(session);
smh->video_last_key_time = now;
}
- if (session->endpoint_interface->io_routines->write_video_frame) {
- if ((status = session->endpoint_interface->io_routines->write_video_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {
- for (ptr = session->event_hooks.video_write_frame; ptr; ptr = ptr->next) {
- if ((status = ptr->video_write_frame(session, frame, flags, stream_id)) != SWITCH_STATUS_SUCCESS) {
- break;
- }
- }
+ if (!img) {
+ return raw_write_video(session, frame, flags, stream_id);
+ }
+
+ if (!(timer = switch_core_media_get_timer(session, SWITCH_MEDIA_TYPE_VIDEO))) {
+
+ if (!smh->video_timer.timer_interface) {
+ switch_core_timer_init(&smh->video_timer, "soft", 1, 90, switch_core_session_get_pool(session));
}
+
+ timer = &smh->video_timer;
}
+
+ frame->timestamp = timer->samplecount;
+ frame->flags &= ~SFF_SAME_IMAGE;
+
+ do {
+ frame->datalen = SWITCH_DEFAULT_VIDEO_SIZE;
+ switch_core_codec_encode_video(codec, frame);
+
+ if (frame->flags & SFF_PICTURE_RESET) {
+ smh->video_init = 0;
+ smh->video_last_key_time = 0;
+ frame->flags &= ~SFF_PICTURE_RESET;
+ }
+
+ switch_set_flag(frame, SFF_RAW_RTP_PARSE_FRAME);
+
+ status = raw_write_video(session, frame, flags, stream_id);
+
+ if (status == SWITCH_STATUS_SUCCESS && session->image_write_callback) {
+ session->image_write_callback(session, frame, img, session->image_write_callback_user_data);
+ }
+
+ } while(frame->datalen);
+
+
return status;
}
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_io_event_hook_video_read_frame_t *ptr;
+ uint32_t loops = 0;
switch_assert(session != NULL);
- if (switch_channel_down(session->channel)) {
+ top:
+
+ loops++;
+
+ if (switch_channel_down_nosig(session->channel)) {
return SWITCH_STATUS_FALSE;
}
}
}
+ if (switch_channel_test_flag(session->channel, CF_VIDEO_DECODED_READ)) {
+ switch_status_t decode_status = switch_core_codec_decode_video((*frame)->codec, *frame);
+
+ if (switch_test_flag((*frame), SFF_WAIT_KEY_FRAME)) {
+ switch_core_session_refresh_video(session);
+ switch_clear_flag((*frame), SFF_WAIT_KEY_FRAME);
+ }
+
+ if (decode_status == SWITCH_STATUS_MORE_DATA) {
+ printf("mo data\n");
+ goto top;
+ }
+ }
+
done:
return status;
{
switch_channel_set_flag(session->channel, CF_VIDEO_ECHO);
switch_channel_clear_flag(session->channel, CF_VIDEO_PASSIVE);
+ switch_channel_clear_flag(session->channel, CF_VIDEO_DECODED_READ);
switch_core_session_refresh_video(session);
session->image_write_callback = NULL;
session->image_write_callback_user_data = NULL;
session_manager.running, session_manager.busy, session_manager.popping);
}
-SWITCH_DECLARE(switch_status_t) switch_core_session_set_video_thread_callback(switch_core_session_t *session, switch_core_video_thread_callback_func_t *func, void *user_data)
-{
- if (!func) {
- session->_video_thread_callback = NULL;
- session->_video_thread_user_data = NULL;
- return SWITCH_STATUS_SUCCESS;
- } else if (session->_video_thread_callback) {
- return SWITCH_STATUS_FALSE;
- } else {
- session->_video_thread_callback = func;
- session->_video_thread_user_data = user_data;
- return SWITCH_STATUS_SUCCESS;
- }
-}
-
-SWITCH_DECLARE(switch_status_t) switch_core_session_video_thread_callback(switch_core_session_t *session, switch_frame_t *frame)
-{
- if (session->_video_thread_callback) {
- return session->_video_thread_callback(session, frame, session->_video_thread_user_data);
- }
-
- return SWITCH_STATUS_CONTINUE;
-}
-
-
/* For Emacs:
* Local Variables:
* mode:c
int up;
};
-static void *SWITCH_THREAD_FUNC video_bridge_thread(switch_thread_t *thread, void *obj)
+static void video_bridge_thread(switch_core_session_t *session, void *obj)
{
struct vid_helper *vh = obj;
switch_channel_t *channel = switch_core_session_get_channel(vh->session_a);
switch_channel_t *b_channel = switch_core_session_get_channel(vh->session_b);
switch_status_t status;
switch_frame_t *read_frame = 0;
- const char *source = switch_channel_get_variable(channel, "source");
- const char *b_source = switch_channel_get_variable(b_channel, "source");
vh->up = 1;
switch_core_session_read_lock(vh->session_a);
switch_core_session_read_lock(vh->session_b);
- if (!switch_stristr("loopback", source) && !switch_stristr("loopback", b_source)) {
- switch_channel_set_flag(channel, CF_VIDEO_PASSIVE);
- //switch_channel_set_flag(b_channel, CF_VIDEO_PASSIVE);
- }
-
switch_core_session_refresh_video(vh->session_a);
switch_core_session_refresh_video(vh->session_b);
while (switch_channel_up_nosig(channel) && switch_channel_up_nosig(b_channel) && vh->up == 1) {
if (switch_channel_media_up(channel)) {
+ switch_codec_t *a_codec = switch_core_session_get_video_read_codec(vh->session_a);
+ switch_codec_t *b_codec = switch_core_session_get_video_write_codec(vh->session_b);
+
+ if (!b_codec || !a_codec || a_codec->implementation->impl_id == b_codec->implementation->impl_id) {
+ //switch_channel_clear_flag(channel, CF_VIDEO_DECODED_READ);
+ } else {
+ //switch_channel_set_flag(channel, CF_VIDEO_DECODED_READ);
+ }
+
+ switch_channel_set_flag(channel, CF_VIDEO_DECODED_READ);
+
status = switch_core_session_read_video_frame(vh->session_a, &read_frame, SWITCH_IO_FLAG_NONE, 0);
if (!SWITCH_READ_ACCEPTABLE(status)) {
switch_cond_next();
continue;
}
+
+ if (!switch_test_flag(read_frame, SFF_CNG)) {
+ switch_core_session_write_video_frame(vh->session_a, read_frame, SWITCH_IO_FLAG_NONE, 0);
+ continue;
+ }
}
if (switch_test_flag(read_frame, SFF_CNG)) {
}
- switch_channel_clear_flag(channel, CF_VIDEO_PASSIVE);
- //switch_channel_clear_flag(b_channel, CF_VIDEO_PASSIVE);
-
switch_core_session_kill_channel(vh->session_b, SWITCH_SIG_BREAK);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(vh->session_a), SWITCH_LOG_DEBUG, "%s video thread ended.\n", switch_channel_get_name(channel));
switch_core_session_rwunlock(vh->session_b);
vh->up = 0;
- return NULL;
+ return;
}
-static switch_thread_t *launch_video(struct vid_helper *vh)
+static void launch_video(struct vid_helper *vh)
{
- switch_thread_t *thread;
- switch_threadattr_t *thd_attr = NULL;
-
- switch_threadattr_create(&thd_attr, switch_core_session_get_pool(vh->session_a));
- switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
- switch_thread_create(&thread, thd_attr, video_bridge_thread, vh, switch_core_session_get_pool(vh->session_a));
- return thread;
+ switch_core_media_start_video_function(vh->session_a, video_bridge_thread, vh);
}
#endif
const char *exec_data = NULL;
#ifdef SWITCH_VIDEO_IN_THREADS
- switch_thread_t *vid_thread = NULL;
struct vid_helper vh = { 0 };
uint32_t vid_launch = 0;
#endif
chan_a = switch_core_session_get_channel(session_a);
chan_b = switch_core_session_get_channel(session_b);
+
+ switch_channel_clear_flag(chan_a, CF_VIDEO_ECHO);
+ switch_channel_clear_flag(chan_b, CF_VIDEO_ECHO);
if ((exec_app = switch_channel_get_variable(chan_a, "bridge_pre_execute_app"))) {
vid_launch++;
vh.session_a = session_a;
vh.session_b = session_b;
- vid_thread = launch_video(&vh);
+ //DFF TEMP
+ if (switch_channel_test_flag(chan_a, CF_BRIDGE_ORIGINATOR)) {
+ launch_video(&vh);
+ }
}
#endif
end_of_bridge_loop:
#ifdef SWITCH_VIDEO_IN_THREADS
- if (vid_thread) {
+ if (vh.up > 0) {
vh.up = -1;
switch_channel_set_flag(chan_a, CF_NOT_READY);
//switch_channel_set_flag(chan_b, CF_NOT_READY);
end:
#ifdef SWITCH_VIDEO_IN_THREADS
- if (vid_thread) {
- switch_status_t st;
-
+ if (switch_core_media_check_video_function(session_a)) {
if (vh.up == 1) {
vh.up = -1;
}
switch_core_session_kill_channel(session_b, SWITCH_SIG_BREAK);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session_a), SWITCH_LOG_DEBUG, "Ending video thread.\n");
- switch_thread_join(&st, vid_thread);
+ switch_core_media_end_video_function(session_a);
switch_channel_clear_flag(chan_a, CF_NOT_READY);
switch_channel_clear_flag(chan_b, CF_NOT_READY);
}
switch_core_session_kill_channel(session_b, SWITCH_SIG_BREAK);
data->done = 1;
+ switch_core_session_video_reset(session_a);
+ switch_core_session_video_reset(session_b);
+
switch_core_session_rwunlock(session_b);
return NULL;
}
static void send_fir(switch_rtp_t *rtp_session)
{
- if (!rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && rtp_session->ice.ice_user) {
+ if (!rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
return;
}
static void send_pli(switch_rtp_t *rtp_session)
{
- if (!rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && rtp_session->ice.ice_user) {
+ if (!rtp_session->flags[SWITCH_RTP_FLAG_VIDEO]) {
return;
}
}
if (rtp_session->pli_countdown) {
-
if (rtp_session->pli_countdown == PLI_COUNTDOWN || (rtp_session->pli_countdown == PLI_COUNTDOWN / 2) || rtp_session->pli_countdown == 1) {
send_pli(rtp_session);
}