static pj_status_t codec_get_frame(pjmedia_port *port, pjmedia_frame *frame) { codec_port_data_t *port_data = (codec_port_data_t*)port->port_data.pdata; pjmedia_vid_codec *codec = port_data->codec; pjmedia_frame enc_frame; pj_status_t status; enc_frame.buf = port_data->enc_buf; enc_frame.size = port_data->enc_buf_size; if (port_data->conv) { pj_size_t frame_size = frame->size; status = pjmedia_port_get_frame(port_data->src_port, frame); if (status != PJ_SUCCESS) goto on_error; status = pjmedia_vid_codec_decode(codec, 1, frame, frame->size, &enc_frame); if (status != PJ_SUCCESS) goto on_error; frame->size = frame_size; status = pjmedia_converter_convert(port_data->conv, &enc_frame, frame); if (status != PJ_SUCCESS) goto on_error; return PJ_SUCCESS; } status = pjmedia_port_get_frame(port_data->src_port, &enc_frame); if (status != PJ_SUCCESS) goto on_error; status = pjmedia_vid_codec_decode(codec, 1, &enc_frame, frame->size, frame); if (status != PJ_SUCCESS) goto on_error; return PJ_SUCCESS; on_error: pj_perror(3, THIS_FILE, status, "codec_get_frame() error"); return status; }
pj_status_t pjmedia_vid_dev_conv_resize_and_rotate(pjmedia_vid_dev_conv *conv, void *src_buf, void **result) { #define swap(a, b) {pj_uint8_t *c = a; a = b; b = c;} pj_status_t status; pjmedia_frame src_frame, dst_frame; pjmedia_rect_size src_size = conv->src_size; pj_uint8_t *src = src_buf; pj_uint8_t *dst = conv->conv_buf; pj_assert(src_buf); if (!conv->conv) return PJ_EINVALIDOP; if (!conv->match_src_dst) { /* We need to resize. */ src_frame.buf = src; dst_frame.buf = dst; src_frame.size = conv->src_frame_size; dst_frame.size = conv->conv_frame_size; status = pjmedia_converter_convert(conv->conv, &src_frame, &dst_frame); if (status != PJ_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Failed to convert frame")); return status; } src_size = conv->res_size; swap(src, dst); } if (conv->handle_rotation && conv->rotation != PJMEDIA_ORIENT_NATURAL) { /* We need to do rotation. */ if (conv->fmt.id == PJMEDIA_FORMAT_I420) { pjmedia_rect_size dst_size = src_size; pj_size_t p_len = src_size.w * src_size.h; if (conv->rotation == PJMEDIA_ORIENT_ROTATE_90DEG || conv->rotation == PJMEDIA_ORIENT_ROTATE_270DEG) { dst_size.w = src_size.h; dst_size.h = src_size.w; } #if defined(PJMEDIA_HAS_LIBYUV) && PJMEDIA_HAS_LIBYUV != 0 enum RotationMode mode; switch (conv->rotation) { case PJMEDIA_ORIENT_ROTATE_90DEG: mode = kRotate90; break; case PJMEDIA_ORIENT_ROTATE_180DEG: mode = kRotate180; break; case PJMEDIA_ORIENT_ROTATE_270DEG: mode = kRotate270; break; default: mode = kRotate0; } I420Rotate(src, src_size.w, src+p_len, src_size.w/2, src+p_len+p_len/4, src_size.w/2, dst, dst_size.w, dst+p_len, dst_size.w/2, dst+p_len+p_len/4, dst_size.w/2, src_size.w, src_size.h, mode); swap(src, dst); #else PJ_UNUSED_ARG(p_len); PJ_UNUSED_ARG(dst_size); #endif } } if (!conv->match_src_dst && conv->maintain_aspect_ratio) { /* Center the frame and fill the area with black color */ if (conv->fmt.id == PJMEDIA_FORMAT_I420) { unsigned i = 0; pj_uint8_t *pdst = dst; pj_uint8_t *psrc = src; pj_size_t p_len_src = 0, p_len_dst = conv->wxh; int pad = conv->pad; pj_bzero(pdst, p_len_dst); if (conv->fit_to_h) { /* Fill the left and right with black */ for (; i < conv->dst_size.h; ++i) { pdst += pad; pj_memcpy(pdst, psrc, conv->rot_size.w); pdst += conv->rot_size.w; psrc += conv->rot_size.w; pdst += pad; } } else { /* Fill the top and bottom with black */ p_len_src = conv->rot_size.w * conv->rot_size.h; pj_memcpy(pdst + conv->rot_size.w * pad, psrc, p_len_src); psrc += p_len_src; pdst += p_len_dst; } /* Fill the U&V components with 0x80 to make it black. * Bzero-ing will make the area look green instead. */ pj_memset(pdst, 0x80, p_len_dst/2); pad /= 2; if (conv->fit_to_h) { p_len_src = conv->rot_size.w / 2; for (i = conv->dst_size.h; i > 0; --i) { pdst += pad; pj_memcpy(pdst, psrc, p_len_src); pdst += p_len_src; psrc += p_len_src; pdst += pad; } } else { pj_uint8_t *U, *V; pj_size_t gap = conv->rot_size.w * pad / 2; p_len_src /= 4; U = pdst; V = U + p_len_dst/4; pj_memcpy(U + gap, psrc, p_len_src); psrc += p_len_src; pj_memcpy(V + gap, psrc, p_len_src); } swap(src, dst); } } *result = src; return PJ_SUCCESS; }
static pj_status_t tee_put_frame(pjmedia_port *port, pjmedia_frame *frame) { vid_tee_port *tee = (vid_tee_port*)port; unsigned i, j; const pj_uint8_t PUT_FRM_DONE = 1; pj_bzero(tee->put_frm_flag, tee->dst_port_cnt * sizeof(tee->put_frm_flag[0])); for (i = 0; i < tee->dst_port_cnt; ++i) { pjmedia_frame frame_ = *frame; if (tee->put_frm_flag[i]) continue; if (tee->tee_conv[i].conv) { pj_status_t status; frame_.buf = tee->buf[0]; frame_.size = tee->tee_conv[i].conv_buf_size; status = pjmedia_converter_convert(tee->tee_conv[i].conv, frame, &frame_); if (status != PJ_SUCCESS) { PJ_LOG(3, (THIS_FILE, "Failed to convert frame for destination" " port %d (%.*s)", i, tee->dst_ports[i].dst->info.name.slen, tee->dst_ports[i].dst->info.name.ptr)); continue; } } /* Find other destination ports which has the same format so * we don't need to do the same conversion twice. */ for (j = i; j < tee->dst_port_cnt; ++j) { pjmedia_frame framep; if (tee->put_frm_flag[j] || (tee->dst_ports[j].dst->info.fmt.id != tee->dst_ports[i].dst->info.fmt.id) || (tee->dst_ports[j].dst->info.fmt.det.vid.size.w != tee->dst_ports[i].dst->info.fmt.det.vid.size.w) || (tee->dst_ports[j].dst->info.fmt.det.vid.size.h != tee->dst_ports[i].dst->info.fmt.det.vid.size.h)) { continue; } framep = frame_; /* For dst_ports that do in-place processing, we need to duplicate * the data source first. */ if (tee->dst_ports[j].option & PJMEDIA_VID_TEE_DST_DO_IN_PLACE_PROC) { PJ_ASSERT_RETURN(tee->buf_size <= frame_.size, PJ_ETOOBIG); framep.buf = tee->buf[tee->buf_cnt-1]; framep.size = frame_.size; pj_memcpy(framep.buf, frame_.buf, frame_.size); } /* Deliver the data */ pjmedia_port_put_frame(tee->dst_ports[j].dst, &framep); tee->put_frm_flag[j] = PUT_FRM_DONE; if (!tee->tee_conv[i].conv) break; } } return PJ_SUCCESS; }