Exemple #1
0
/* API: Get frame from stream */
static pj_status_t ffmpeg_stream_get_frame(pjmedia_vid_dev_stream *s,
                                           pjmedia_frame *frame)
{
    ffmpeg_stream *strm = (ffmpeg_stream*)s;
    AVPacket p;
    int err;

    err = av_read_frame(strm->ff_fmt_ctx, &p);
    if (err < 0) {
        print_ffmpeg_err(err);
        return PJ_EUNKNOWN;
    }

    pj_bzero(frame, sizeof(*frame));
    frame->type = PJMEDIA_FRAME_TYPE_VIDEO;
    frame->buf = p.data;
    frame->size = p.size;

    return PJ_SUCCESS;
}
Exemple #2
0
static pj_status_t ffmpeg_capture_open(AVFormatContext **ctx,
                                       AVInputFormat *ifmt,
                                       const char *dev_name,
                                       const pjmedia_vid_dev_param *param)
{
    AVFormatParameters fp;
    pjmedia_video_format_detail *vfd;
    int err;

    PJ_ASSERT_RETURN(ctx && ifmt && dev_name && param, PJ_EINVAL);
    PJ_ASSERT_RETURN(param->fmt.detail_type == PJMEDIA_FORMAT_DETAIL_VIDEO,
                     PJ_EINVAL);

    vfd = pjmedia_format_get_video_format_detail(&param->fmt, PJ_TRUE);

    /* Init ffmpeg format context */
    *ctx = avformat_alloc_context();

    /* Init ffmpeg format param */
    pj_bzero(&fp, sizeof(fp));
    fp.prealloced_context = 1;
    fp.width = vfd->size.w;
    fp.height = vfd->size.h;
    fp.pix_fmt = PIX_FMT_BGR24;
    fp.time_base.num = vfd->fps.denum;
    fp.time_base.den = vfd->fps.num;

    /* Open capture stream */
    err = av_open_input_stream(ctx, NULL, dev_name, ifmt, &fp);
    if (err < 0) {
        *ctx = NULL; /* ffmpeg freed its states on failure, do we must too */
        print_ffmpeg_err(err);
        return PJ_EUNKNOWN;
    }

    return PJ_SUCCESS;
}
Exemple #3
0
/*
 * Encode frames.
 */
static pj_status_t ffmpeg_codec_encode_whole(pjmedia_vid_codec *codec,
					     const pjmedia_vid_encode_opt *opt,
					     const pjmedia_frame *input,
					     unsigned output_buf_len,
					     pjmedia_frame *output)
{
    ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
    pj_uint8_t *p = (pj_uint8_t*)input->buf;
    AVFrame avframe;
    pj_uint8_t *out_buf = (pj_uint8_t*)output->buf;
    int out_buf_len = output_buf_len;
    int err;
    //AVRational src_timebase;
    /* For some reasons (e.g: SSE/MMX usage), the avcodec_encode_video() must
     * have stack aligned to 16 bytes. Let's try to be safe by preparing the
     * 16-bytes aligned stack here, in case it's not managed by the ffmpeg.
     */
    PJ_ALIGN_DATA(pj_uint32_t i[4], 16);

    if ((long)i & 0xF) {
	PJ_LOG(2,(THIS_FILE, "Stack alignment fails"));
    }

    /* Check if encoder has been opened */
    PJ_ASSERT_RETURN(ff->enc_ctx, PJ_EINVALIDOP);

    avcodec_get_frame_defaults(&avframe);

    // Let ffmpeg manage the timestamps
    /*
    src_timebase.num = 1;
    src_timebase.den = ff->desc->info.clock_rate;
    avframe.pts = av_rescale_q(input->timestamp.u64, src_timebase,
			       ff->enc_ctx->time_base);
    */
    
    for (i[0] = 0; i[0] < ff->enc_vfi->plane_cnt; ++i[0]) {
        avframe.data[i[0]] = p;
        avframe.linesize[i[0]] = ff->enc_vafp.strides[i[0]];
        p += ff->enc_vafp.plane_bytes[i[0]];
    }

    /* Force keyframe */
    if (opt && opt->force_keyframe) {
#if LIBAVCODEC_VER_AT_LEAST(53,20)
	avframe.pict_type = AV_PICTURE_TYPE_I;
#else
	avframe.pict_type = FF_I_TYPE;
#endif
    }

    err = avcodec_encode_video(ff->enc_ctx, out_buf, out_buf_len, &avframe);
    if (err < 0) {
        print_ffmpeg_err(err);
        return PJMEDIA_CODEC_EFAILED;
    } else {
        output->size = err;
	output->bit_info = 0;
	if (ff->enc_ctx->coded_frame->key_frame)
	    output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
    }

    return PJ_SUCCESS;
}
Exemple #4
0
/*
 * Decode frame.
 */
static pj_status_t ffmpeg_codec_decode_whole(pjmedia_vid_codec *codec,
					     const pjmedia_frame *input,
					     unsigned output_buf_len,
					     pjmedia_frame *output)
{
    ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
    AVFrame avframe;
    AVPacket avpacket;
    int err, got_picture;

    /* Check if decoder has been opened */
    PJ_ASSERT_RETURN(ff->dec_ctx, PJ_EINVALIDOP);

    /* Reset output frame bit info */
    output->bit_info = 0;

    /* Validate output buffer size */
    // Do this validation later after getting decoding result, where the real
    // decoded size will be assured.
    //if (ff->dec_vafp.framebytes > output_buf_len)
	//return PJ_ETOOSMALL;

    /* Init frame to receive the decoded data, the ffmpeg codec context will
     * automatically provide the decoded buffer (single buffer used for the
     * whole decoding session, and seems to be freed when the codec context
     * closed).
     */
    avcodec_get_frame_defaults(&avframe);

    /* Init packet, the container of the encoded data */
    av_init_packet(&avpacket);
    avpacket.data = (pj_uint8_t*)input->buf;
    avpacket.size = input->size;

    /* ffmpeg warns:
     * - input buffer padding, at least FF_INPUT_BUFFER_PADDING_SIZE
     * - null terminated
     * Normally, encoded buffer is allocated more than needed, so lets just
     * bzero the input buffer end/pad, hope it will be just fine.
     */
    pj_bzero(avpacket.data+avpacket.size, FF_INPUT_BUFFER_PADDING_SIZE);

    output->bit_info = 0;
    output->timestamp = input->timestamp;

#if LIBAVCODEC_VER_AT_LEAST(52,72)
    //avpacket.flags = AV_PKT_FLAG_KEY;
#else
    avpacket.flags = 0;
#endif

#if LIBAVCODEC_VER_AT_LEAST(52,72)
    err = avcodec_decode_video2(ff->dec_ctx, &avframe, 
                                &got_picture, &avpacket);
#else
    err = avcodec_decode_video(ff->dec_ctx, &avframe,
                               &got_picture, avpacket.data, avpacket.size);
#endif
    if (err < 0) {
	pjmedia_event event;

	output->type = PJMEDIA_FRAME_TYPE_NONE;
	output->size = 0;
        print_ffmpeg_err(err);

	/* Broadcast missing keyframe event */
	pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING,
			   &input->timestamp, codec);
	pjmedia_event_publish(NULL, codec, &event, 0);

	return PJMEDIA_CODEC_EBADBITSTREAM;
    } else if (got_picture) {
        pjmedia_video_apply_fmt_param *vafp = &ff->dec_vafp;
        pj_uint8_t *q = (pj_uint8_t*)output->buf;
	unsigned i;
	pj_status_t status;

	/* Check decoding result, e.g: see if the format got changed,
	 * keyframe found/missing.
	 */
	status = check_decode_result(codec, &input->timestamp,
				     avframe.key_frame);
	if (status != PJ_SUCCESS)
	    return status;

	/* Check provided buffer size */
	if (vafp->framebytes > output_buf_len)
	    return PJ_ETOOSMALL;

	/* Get the decoded data */
	for (i = 0; i < ff->dec_vfi->plane_cnt; ++i) {
	    pj_uint8_t *p = avframe.data[i];

	    /* The decoded data may contain padding */
	    if (avframe.linesize[i]!=vafp->strides[i]) {
		/* Padding exists, copy line by line */
		pj_uint8_t *q_end;
                    
		q_end = q+vafp->plane_bytes[i];
		while(q < q_end) {
		    pj_memcpy(q, p, vafp->strides[i]);
		    q += vafp->strides[i];
		    p += avframe.linesize[i];
		}
	    } else {
		/* No padding, copy the whole plane */
		pj_memcpy(q, p, vafp->plane_bytes[i]);
		q += vafp->plane_bytes[i];
	    }
	}

	output->type = PJMEDIA_FRAME_TYPE_VIDEO;
        output->size = vafp->framebytes;
    } else {
	output->type = PJMEDIA_FRAME_TYPE_NONE;
	output->size = 0;
    }
    
    return PJ_SUCCESS;
}
Exemple #5
0
static pj_status_t open_ffmpeg_codec(ffmpeg_private *ff,
                                     pj_mutex_t *ff_mutex)
{
    enum PixelFormat pix_fmt;
    pjmedia_video_format_detail *vfd;
    pj_bool_t enc_opened = PJ_FALSE, dec_opened = PJ_FALSE;
    pj_status_t status;

    /* Get decoded pixel format */
    status = pjmedia_format_id_to_PixelFormat(ff->param.dec_fmt.id,
                                              &pix_fmt);
    if (status != PJ_SUCCESS)
        return status;
    ff->expected_dec_fmt = pix_fmt;

    /* Get video format detail for shortcut access to encoded format */
    vfd = pjmedia_format_get_video_format_detail(&ff->param.enc_fmt, 
						 PJ_TRUE);

    /* Allocate ffmpeg codec context */
    if (ff->param.dir & PJMEDIA_DIR_ENCODING) {
#if LIBAVCODEC_VER_AT_LEAST(53,20)
	ff->enc_ctx = avcodec_alloc_context3(ff->enc);
#else
	ff->enc_ctx = avcodec_alloc_context();
#endif
	if (ff->enc_ctx == NULL)
	    goto on_error;
    }
    if (ff->param.dir & PJMEDIA_DIR_DECODING) {
#if LIBAVCODEC_VER_AT_LEAST(53,20)
	ff->dec_ctx = avcodec_alloc_context3(ff->dec);
#else
	ff->dec_ctx = avcodec_alloc_context();
#endif
	if (ff->dec_ctx == NULL)
	    goto on_error;
    }

    /* Init generic encoder params */
    if (ff->param.dir & PJMEDIA_DIR_ENCODING) {
        AVCodecContext *ctx = ff->enc_ctx;

        ctx->pix_fmt = pix_fmt;
	ctx->width = vfd->size.w;
	ctx->height = vfd->size.h;
	ctx->time_base.num = vfd->fps.denum;
	ctx->time_base.den = vfd->fps.num;
	if (vfd->avg_bps) {
	    ctx->bit_rate = vfd->avg_bps;
	    if (vfd->max_bps > vfd->avg_bps)
		ctx->bit_rate_tolerance = vfd->max_bps - vfd->avg_bps;
	}
	ctx->strict_std_compliance = FF_COMPLIANCE_STRICT;
        ctx->workaround_bugs = FF_BUG_AUTODETECT;
        ctx->opaque = ff;

	/* Set no delay, note that this may cause some codec functionals
	 * not working (e.g: rate control).
	 */
#if LIBAVCODEC_VER_AT_LEAST(52,113)
	ctx->rc_lookahead = 0;
#endif
    }

    /* Init generic decoder params */
    if (ff->param.dir & PJMEDIA_DIR_DECODING) {
	AVCodecContext *ctx = ff->dec_ctx;

	/* Width/height may be overriden by ffmpeg after first decoding. */
	ctx->width  = ctx->coded_width  = ff->param.dec_fmt.det.vid.size.w;
	ctx->height = ctx->coded_height = ff->param.dec_fmt.det.vid.size.h;
	ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
        ctx->workaround_bugs = FF_BUG_AUTODETECT;
        ctx->opaque = ff;
    }

    /* Override generic params or apply specific params before opening
     * the codec.
     */
    if (ff->desc->preopen) {
	status = (*ff->desc->preopen)(ff);
	if (status != PJ_SUCCESS)
	    goto on_error;
    }

    /* Open encoder */
    if (ff->param.dir & PJMEDIA_DIR_ENCODING) {
	int err;

	pj_mutex_lock(ff_mutex);
	err = avcodec_open(ff->enc_ctx, ff->enc);
        pj_mutex_unlock(ff_mutex);
        if (err < 0) {
            print_ffmpeg_err(err);
            status = PJMEDIA_CODEC_EFAILED;
	    goto on_error;
        }
	enc_opened = PJ_TRUE;
    }

    /* Open decoder */
    if (ff->param.dir & PJMEDIA_DIR_DECODING) {
	int err;

	pj_mutex_lock(ff_mutex);
	err = avcodec_open(ff->dec_ctx, ff->dec);
        pj_mutex_unlock(ff_mutex);
        if (err < 0) {
            print_ffmpeg_err(err);
            status = PJMEDIA_CODEC_EFAILED;
	    goto on_error;
        }
	dec_opened = PJ_TRUE;
    }

    /* Let the codec apply specific params after the codec opened */
    if (ff->desc->postopen) {
	status = (*ff->desc->postopen)(ff);
	if (status != PJ_SUCCESS)
	    goto on_error;
    }

    return PJ_SUCCESS;

on_error:
    if (ff->enc_ctx) {
	if (enc_opened)
	    avcodec_close(ff->enc_ctx);
	av_free(ff->enc_ctx);
	ff->enc_ctx = NULL;
    }
    if (ff->dec_ctx) {
	if (dec_opened)
	    avcodec_close(ff->dec_ctx);
	av_free(ff->dec_ctx);
	ff->dec_ctx = NULL;
    }
    return status;
}