diff options
Diffstat (limited to 'modules/avcodec')
-rw-r--r-- | modules/avcodec/avcodec.c | 176 | ||||
-rw-r--r-- | modules/avcodec/avcodec.h | 62 | ||||
-rw-r--r-- | modules/avcodec/decode.c | 346 | ||||
-rw-r--r-- | modules/avcodec/encode.c | 646 | ||||
-rw-r--r-- | modules/avcodec/h263.c | 176 | ||||
-rw-r--r-- | modules/avcodec/h264.c | 188 | ||||
-rw-r--r-- | modules/avcodec/h26x.h | 165 | ||||
-rw-r--r-- | modules/avcodec/module.mk | 20 |
8 files changed, 1779 insertions, 0 deletions
diff --git a/modules/avcodec/avcodec.c b/modules/avcodec/avcodec.c new file mode 100644 index 0000000..d6ce3de --- /dev/null +++ b/modules/avcodec/avcodec.c @@ -0,0 +1,176 @@ +/** + * @file avcodec.c Video codecs using FFmpeg libavcodec + * + * Copyright (C) 2010 Creytiv.com + */ +#include <re.h> +#include <rem.h> +#include <baresip.h> +#include <libavcodec/avcodec.h> +#ifdef USE_X264 +#include <x264.h> +#endif +#include "h26x.h" +#include "avcodec.h" + + +int avcodec_resolve_codecid(const char *s) +{ + if (0 == str_casecmp(s, "H263")) + return CODEC_ID_H263; + else if (0 == str_casecmp(s, "H264")) + return CODEC_ID_H264; + else if (0 == str_casecmp(s, "MP4V-ES")) + return CODEC_ID_MPEG4; + else + return CODEC_ID_NONE; +} + + +static uint32_t packetization_mode(const char *fmtp) +{ + struct pl pl, mode; + + if (!fmtp) + return 0; + + pl_set_str(&pl, fmtp); + + if (fmt_param_get(&pl, "packetization-mode", &mode)) + return pl_u32(&mode); + + return 0; +} + + +static int h264_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, + bool offer, void *arg) +{ + struct vidcodec *vc = arg; + const uint8_t profile_idc = 0x42; /* baseline profile */ + const uint8_t profile_iop = 0x80; + (void)offer; + + if (!mb || !fmt || !vc) + return 0; + + return mbuf_printf(mb, "a=fmtp:%s" + " packetization-mode=0" + ";profile-level-id=%02x%02x%02x" + "\r\n", + fmt->id, profile_idc, profile_iop, h264_level_idc); +} + + +static bool h264_fmtp_cmp(const char *fmtp1, const char *fmtp2, void *data) +{ + (void)data; + + return packetization_mode(fmtp1) == packetization_mode(fmtp2); +} + + +static int h263_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, + bool offer, void *arg) +{ + (void)offer; + (void)arg; + + if (!mb || !fmt) + return 0; + + return mbuf_printf(mb, "a=fmtp:%s CIF=1;CIF4=1\r\n", fmt->id); +} + + +static int mpg4_fmtp_enc(struct mbuf *mb, const struct sdp_format *fmt, + bool offer, void *arg) +{ + (void)offer; + (void)arg; + + if (!mb || !fmt) + return 0; + + return mbuf_printf(mb, "a=fmtp:%s profile-level-id=3\r\n", fmt->id); +} + + +static struct vidcodec h264 = { + .name = "H264", + .variant = "packetization-mode=0", + .encupdh = encode_update, +#ifdef USE_X264 + .ench = encode_x264, +#else + .ench = encode, +#endif + .decupdh = decode_update, + .dech = decode_h264, + .fmtp_ench = h264_fmtp_enc, + .fmtp_cmph = h264_fmtp_cmp, +}; + +static struct vidcodec h263 = { + .pt = "34", + .name = "H263", + .encupdh = encode_update, + .ench = encode, + .decupdh = decode_update, + .dech = decode_h263, + .fmtp_ench = h263_fmtp_enc, +}; + +static struct vidcodec mpg4 = { + .name = "MP4V-ES", + .encupdh = encode_update, + .ench = encode, + .decupdh = decode_update, + .dech = decode_mpeg4, + .fmtp_ench = mpg4_fmtp_enc, +}; + + +static int module_init(void) +{ +#ifdef USE_X264 + debug("avcodec: x264 build %d\n", X264_BUILD); +#else + debug("avcodec: using FFmpeg H.264 encoder\n"); +#endif + +#if LIBAVCODEC_VERSION_INT < ((53<<16)+(10<<8)+0) + avcodec_init(); +#endif + + avcodec_register_all(); + + if (avcodec_find_decoder(CODEC_ID_H264)) + vidcodec_register(&h264); + + if (avcodec_find_decoder(CODEC_ID_H263)) + vidcodec_register(&h263); + + if (avcodec_find_decoder(CODEC_ID_MPEG4)) + vidcodec_register(&mpg4); + + return 0; +} + + +static int module_close(void) +{ + vidcodec_unregister(&mpg4); + vidcodec_unregister(&h263); + vidcodec_unregister(&h264); + + return 0; +} + + +EXPORT_SYM const struct mod_export DECL_EXPORTS(avcodec) = { + "avcodec", + "codec", + module_init, + module_close +}; diff --git a/modules/avcodec/avcodec.h b/modules/avcodec/avcodec.h new file mode 100644 index 0000000..bbd022a --- /dev/null +++ b/modules/avcodec/avcodec.h @@ -0,0 +1,62 @@ +/** + * @file avcodec.h Video codecs using FFmpeg libavcodec -- internal API + * + * Copyright (C) 2010 Creytiv.com + */ + + +#if LIBAVCODEC_VERSION_INT >= ((54<<16)+(25<<8)+0) +#define CodecID AVCodecID +#endif + + +extern const uint8_t h264_level_idc; + + +/* + * Encode + */ + +struct videnc_state; + +int encode_update(struct videnc_state **vesp, const struct vidcodec *vc, + struct videnc_param *prm, const char *fmtp); +int encode(struct videnc_state *st, bool update, const struct vidframe *frame, + videnc_packet_h *pkth, void *arg); +#ifdef USE_X264 +int encode_x264(struct videnc_state *st, bool update, + const struct vidframe *frame, + videnc_packet_h *pkth, void *arg); +#endif + + +/* + * Decode + */ + +struct viddec_state; + +int decode_update(struct viddec_state **vdsp, const struct vidcodec *vc, + const char *fmtp); +int decode_h263(struct viddec_state *st, struct vidframe *frame, + bool eof, uint16_t seq, struct mbuf *src); +int decode_h264(struct viddec_state *st, struct vidframe *frame, + bool eof, uint16_t seq, struct mbuf *src); +int decode_mpeg4(struct viddec_state *st, struct vidframe *frame, + bool eof, uint16_t seq, struct mbuf *src); +int decode_h263_test(struct viddec_state *st, struct vidframe *frame, + bool marker, uint16_t seq, struct mbuf *src); + + +int decode_sdpparam_h264(struct videnc_state *st, const struct pl *name, + const struct pl *val); +int h264_packetize(struct mbuf *mb, size_t pktsize, + videnc_packet_h *pkth, void *arg); +int h264_decode(struct viddec_state *st, struct mbuf *src); +int h264_nal_send(bool first, bool last, + bool marker, uint32_t ihdr, const uint8_t *buf, + size_t size, size_t maxsz, + videnc_packet_h *pkth, void *arg); + + +int avcodec_resolve_codecid(const char *s); diff --git a/modules/avcodec/decode.c b/modules/avcodec/decode.c new file mode 100644 index 0000000..36550a7 --- /dev/null +++ b/modules/avcodec/decode.c @@ -0,0 +1,346 @@ +/** + * @file avcodec/decode.c Video codecs using FFmpeg libavcodec -- decoder + * + * Copyright (C) 2010 - 2013 Creytiv.com + */ +#include <re.h> +#include <rem.h> +#include <baresip.h> +#include <libavcodec/avcodec.h> +#include <libavutil/mem.h> +#include "h26x.h" +#include "avcodec.h" + + +struct viddec_state { + AVCodec *codec; + AVCodecContext *ctx; + AVFrame *pict; + struct mbuf *mb; + bool got_keyframe; +}; + + +static void destructor(void *arg) +{ + struct viddec_state *st = arg; + + mem_deref(st->mb); + + if (st->ctx) { + if (st->ctx->codec) + avcodec_close(st->ctx); + av_free(st->ctx); + } + + if (st->pict) + av_free(st->pict); +} + + +static int init_decoder(struct viddec_state *st, const char *name) +{ + enum CodecID codec_id; + + codec_id = avcodec_resolve_codecid(name); + if (codec_id == CODEC_ID_NONE) + return EINVAL; + + st->codec = avcodec_find_decoder(codec_id); + if (!st->codec) + return ENOENT; + +#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(92<<8)+0) + st->ctx = avcodec_alloc_context3(st->codec); +#else + st->ctx = avcodec_alloc_context(); +#endif + +#if LIBAVUTIL_VERSION_INT >= ((52<<16)+(20<<8)+100) + st->pict = av_frame_alloc(); +#else + st->pict = avcodec_alloc_frame(); +#endif + + if (!st->ctx || !st->pict) + return ENOMEM; + +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + if (avcodec_open2(st->ctx, st->codec, NULL) < 0) + return ENOENT; +#else + if (avcodec_open(st->ctx, st->codec) < 0) + return ENOENT; +#endif + + return 0; +} + + +int decode_update(struct viddec_state **vdsp, const struct vidcodec *vc, + const char *fmtp) +{ + struct viddec_state *st; + int err = 0; + + if (!vdsp || !vc) + return EINVAL; + + if (*vdsp) + return 0; + + (void)fmtp; + + st = mem_zalloc(sizeof(*st), destructor); + if (!st) + return ENOMEM; + + st->mb = mbuf_alloc(1024); + if (!st->mb) { + err = ENOMEM; + goto out; + } + + err = init_decoder(st, vc->name); + if (err) { + warning("avcodec: %s: could not init decoder\n", vc->name); + goto out; + } + + debug("avcodec: video decoder %s (%s)\n", vc->name, fmtp); + + out: + if (err) + mem_deref(st); + else + *vdsp = st; + + return err; +} + + +/* + * TODO: check input/output size + */ +static int ffdecode(struct viddec_state *st, struct vidframe *frame, + bool eof, struct mbuf *src) +{ + int i, got_picture, ret, err; + + /* assemble packets in "mbuf" */ + err = mbuf_write_mem(st->mb, mbuf_buf(src), mbuf_get_left(src)); + if (err) + return err; + + if (!eof) + return 0; + + st->mb->pos = 0; + + if (!st->got_keyframe) { + err = EPROTO; + goto out; + } + +#if LIBAVCODEC_VERSION_INT <= ((52<<16)+(23<<8)+0) + ret = avcodec_decode_video(st->ctx, st->pict, &got_picture, + st->mb->buf, + (int)mbuf_get_left(st->mb)); +#else + do { + AVPacket avpkt; + + av_init_packet(&avpkt); + avpkt.data = st->mb->buf; + avpkt.size = (int)mbuf_get_left(st->mb); + + ret = avcodec_decode_video2(st->ctx, st->pict, + &got_picture, &avpkt); + } while (0); +#endif + + if (ret < 0) { + err = EBADMSG; + goto out; + } + + mbuf_skip_to_end(src); + + if (got_picture) { + for (i=0; i<4; i++) { + frame->data[i] = st->pict->data[i]; + frame->linesize[i] = st->pict->linesize[i]; + } + frame->size.w = st->ctx->width; + frame->size.h = st->ctx->height; + frame->fmt = VID_FMT_YUV420P; + } + + out: + if (eof) + mbuf_rewind(st->mb); + + return err; +} + + +int h264_decode(struct viddec_state *st, struct mbuf *src) +{ + struct h264_hdr h264_hdr; + const uint8_t nal_seq[3] = {0, 0, 1}; + int err; + + err = h264_hdr_decode(&h264_hdr, src); + if (err) + return err; + + if (h264_hdr.f) { + info("avcodec: H264 forbidden bit set!\n"); + return EBADMSG; + } + + /* handle NAL types */ + if (1 <= h264_hdr.type && h264_hdr.type <= 23) { + + if (!st->got_keyframe) { + switch (h264_hdr.type) { + + case H264_NAL_PPS: + case H264_NAL_SPS: + st->got_keyframe = true; + break; + } + } + + /* prepend H.264 NAL start sequence */ + mbuf_write_mem(st->mb, nal_seq, 3); + + /* encode NAL header back to buffer */ + err = h264_hdr_encode(&h264_hdr, st->mb); + } + else if (H264_NAL_FU_A == h264_hdr.type) { + struct fu fu; + + err = fu_hdr_decode(&fu, src); + if (err) + return err; + h264_hdr.type = fu.type; + + if (fu.s) { + /* prepend H.264 NAL start sequence */ + mbuf_write_mem(st->mb, nal_seq, 3); + + /* encode NAL header back to buffer */ + err = h264_hdr_encode(&h264_hdr, st->mb); + } + } + else { + warning("avcodec: unknown NAL type %u\n", h264_hdr.type); + return EBADMSG; + } + + return err; +} + + +int decode_h264(struct viddec_state *st, struct vidframe *frame, + bool eof, uint16_t seq, struct mbuf *src) +{ + int err; + + (void)seq; + + if (!src) + return 0; + + err = h264_decode(st, src); + if (err) + return err; + + return ffdecode(st, frame, eof, src); +} + + +int decode_mpeg4(struct viddec_state *st, struct vidframe *frame, + bool eof, uint16_t seq, struct mbuf *src) +{ + if (!src) + return 0; + + (void)seq; + + /* let the decoder handle this */ + st->got_keyframe = true; + + return ffdecode(st, frame, eof, src); +} + + +int decode_h263(struct viddec_state *st, struct vidframe *frame, + bool marker, uint16_t seq, struct mbuf *src) +{ + struct h263_hdr hdr; + int err; + + if (!st || !frame) + return EINVAL; + + if (!src) + return 0; + + (void)seq; + + err = h263_hdr_decode(&hdr, src); + if (err) + return err; + +#if 0 + debug(".....[%s seq=%5u ] MODE %s -" + " SBIT=%u EBIT=%u I=%s" + " (%5u/%5u bytes)\n", + marker ? "M" : " ", seq, + h263_hdr_mode(&hdr) == H263_MODE_A ? "A" : "B", + hdr.sbit, hdr.ebit, hdr.i ? "Inter" : "Intra", + mbuf_get_left(src), st->mb->end); +#endif + + if (!hdr.i) + st->got_keyframe = true; + +#if 0 + if (st->mb->pos == 0) { + uint8_t *p = mbuf_buf(src); + + if (p[0] != 0x00 || p[1] != 0x00) { + warning("invalid PSC detected (%02x %02x)\n", + p[0], p[1]); + return EPROTO; + } + } +#endif + + /* + * The H.263 Bit-stream can be fragmented on bit-level, + * indicated by SBIT and EBIT. Example: + * + * 8 bit 2 bit + * .--------.--. + * Packet 1 | | | + * SBIT=0 '--------'--' + * EBIT=6 + * .------.--------.--------. + * Packet 2 | | | | + * SBIT=2 '------'--------'--------' + * EBIT=0 6bit 8bit 8bit + * + */ + + if (hdr.sbit > 0) { + const uint8_t mask = (1 << (8 - hdr.sbit)) - 1; + const uint8_t sbyte = mbuf_read_u8(src) & mask; + + st->mb->buf[st->mb->end - 1] |= sbyte; + } + + return ffdecode(st, frame, marker, src); +} diff --git a/modules/avcodec/encode.c b/modules/avcodec/encode.c new file mode 100644 index 0000000..559c53e --- /dev/null +++ b/modules/avcodec/encode.c @@ -0,0 +1,646 @@ +/** + * @file avcodec/encode.c Video codecs using FFmpeg libavcodec -- encoder + * + * Copyright (C) 2010 - 2013 Creytiv.com + */ +#include <re.h> +#include <rem.h> +#include <baresip.h> +#include <libavcodec/avcodec.h> +#include <libavutil/mem.h> +#ifdef USE_X264 +#include <x264.h> +#endif +#include "h26x.h" +#include "avcodec.h" + + +enum { + DEFAULT_GOP_SIZE = 10, +}; + + +struct picsz { + enum h263_fmt fmt; /**< Picture size */ + uint8_t mpi; /**< Minimum Picture Interval (1-32) */ +}; + + +struct videnc_state { + AVCodec *codec; + AVCodecContext *ctx; + AVFrame *pict; + struct mbuf *mb; + size_t sz_max; /* todo: figure out proper buffer size */ + int64_t pts; + struct mbuf *mb_frag; + struct videnc_param encprm; + struct vidsz encsize; + enum CodecID codec_id; + + union { + struct { + struct picsz picszv[8]; + uint32_t picszn; + } h263; + + struct { + uint32_t packetization_mode; + uint32_t profile_idc; + uint32_t profile_iop; + uint32_t level_idc; + uint32_t max_fs; + uint32_t max_smbps; + } h264; + } u; + +#ifdef USE_X264 + x264_t *x264; +#endif +}; + + +static void destructor(void *arg) +{ + struct videnc_state *st = arg; + + mem_deref(st->mb); + mem_deref(st->mb_frag); + +#ifdef USE_X264 + if (st->x264) + x264_encoder_close(st->x264); +#endif + + if (st->ctx) { + if (st->ctx->codec) + avcodec_close(st->ctx); + av_free(st->ctx); + } + + if (st->pict) + av_free(st->pict); +} + + +static enum h263_fmt h263_fmt(const struct pl *name) +{ + if (0 == pl_strcasecmp(name, "sqcif")) return H263_FMT_SQCIF; + if (0 == pl_strcasecmp(name, "qcif")) return H263_FMT_QCIF; + if (0 == pl_strcasecmp(name, "cif")) return H263_FMT_CIF; + if (0 == pl_strcasecmp(name, "cif4")) return H263_FMT_4CIF; + if (0 == pl_strcasecmp(name, "cif16")) return H263_FMT_16CIF; + return H263_FMT_OTHER; +} + + +static int decode_sdpparam_h263(struct videnc_state *st, const struct pl *name, + const struct pl *val) +{ + enum h263_fmt fmt = h263_fmt(name); + const int mpi = pl_u32(val); + + if (fmt == H263_FMT_OTHER) { + info("h263: unknown param '%r'\n", name); + return 0; + } + if (mpi < 1 || mpi > 32) { + info("h263: %r: MPI out of range %d\n", name, mpi); + return 0; + } + + if (st->u.h263.picszn >= ARRAY_SIZE(st->u.h263.picszv)) { + info("h263: picszv overflow: %r\n", name); + return 0; + } + + st->u.h263.picszv[st->u.h263.picszn].fmt = fmt; + st->u.h263.picszv[st->u.h263.picszn].mpi = mpi; + + ++st->u.h263.picszn; + + return 0; +} + + +static int init_encoder(struct videnc_state *st) +{ + st->codec = avcodec_find_encoder(st->codec_id); + if (!st->codec) + return ENOENT; + + return 0; +} + + +static int open_encoder(struct videnc_state *st, + const struct videnc_param *prm, + const struct vidsz *size) +{ + int err = 0; + + if (st->ctx) { + if (st->ctx->codec) + avcodec_close(st->ctx); + av_free(st->ctx); + } + + if (st->pict) + av_free(st->pict); + +#if LIBAVCODEC_VERSION_INT >= ((52<<16)+(92<<8)+0) + st->ctx = avcodec_alloc_context3(st->codec); +#else + st->ctx = avcodec_alloc_context(); +#endif + +#if LIBAVUTIL_VERSION_INT >= ((52<<16)+(20<<8)+100) + st->pict = av_frame_alloc(); +#else + st->pict = avcodec_alloc_frame(); +#endif + + if (!st->ctx || !st->pict) { + err = ENOMEM; + goto out; + } + + st->ctx->bit_rate = prm->bitrate; + st->ctx->width = size->w; + st->ctx->height = size->h; + st->ctx->gop_size = DEFAULT_GOP_SIZE; + st->ctx->pix_fmt = PIX_FMT_YUV420P; + st->ctx->time_base.num = 1; + st->ctx->time_base.den = prm->fps; + + /* params to avoid ffmpeg/x264 default preset error */ + if (st->codec_id == CODEC_ID_H264) { + st->ctx->me_method = ME_UMH; + st->ctx->me_range = 16; + st->ctx->qmin = 10; + st->ctx->qmax = 51; + st->ctx->max_qdiff = 4; + } + +#if LIBAVCODEC_VERSION_INT >= ((53<<16)+(8<<8)+0) + if (avcodec_open2(st->ctx, st->codec, NULL) < 0) { + err = ENOENT; + goto out; + } +#else + if (avcodec_open(st->ctx, st->codec) < 0) { + err = ENOENT; + goto out; + } +#endif + + out: + if (err) { + if (st->ctx) { + if (st->ctx->codec) + avcodec_close(st->ctx); + av_free(st->ctx); + st->ctx = NULL; + } + + if (st->pict) { + av_free(st->pict); + st->pict = NULL; + } + } + else + st->encsize = *size; + + return err; +} + + +int decode_sdpparam_h264(struct videnc_state *st, const struct pl *name, + const struct pl *val) +{ + if (0 == pl_strcasecmp(name, "packetization-mode")) { + st->u.h264.packetization_mode = pl_u32(val); + + if (st->u.h264.packetization_mode != 0) { + warning("avcodec: illegal packetization-mode %u\n", + st->u.h264.packetization_mode); + return EPROTO; + } + } + else if (0 == pl_strcasecmp(name, "profile-level-id")) { + struct pl prof = *val; + if (prof.l != 6) { + warning("avcodec: invalid profile-level-id (%r)\n", + val); + return EPROTO; + } + + prof.l = 2; + st->u.h264.profile_idc = pl_x32(&prof); prof.p += 2; + st->u.h264.profile_iop = pl_x32(&prof); prof.p += 2; + st->u.h264.level_idc = pl_x32(&prof); + } + else if (0 == pl_strcasecmp(name, "max-fs")) { + st->u.h264.max_fs = pl_u32(val); + } + else if (0 == pl_strcasecmp(name, "max-smbps")) { + st->u.h264.max_smbps = pl_u32(val); + } + + return 0; +} + + +static void param_handler(const struct pl *name, const struct pl *val, + void *arg) +{ + struct videnc_state *st = arg; + + if (st->codec_id == CODEC_ID_H263) + (void)decode_sdpparam_h263(st, name, val); + else if (st->codec_id == CODEC_ID_H264) + (void)decode_sdpparam_h264(st, name, val); +} + + +static int general_packetize(struct mbuf *mb, size_t pktsize, + videnc_packet_h *pkth, void *arg) +{ + int err = 0; + + /* Assemble frame into smaller packets */ + while (!err) { + size_t sz, left = mbuf_get_left(mb); + bool last = (left < pktsize); + if (!left) + break; + + sz = last ? left : pktsize; + + err = pkth(last, NULL, 0, mbuf_buf(mb), sz, arg); + + mbuf_advance(mb, sz); + } + + return err; +} + + +static int h263_packetize(struct videnc_state *st, struct mbuf *mb, + videnc_packet_h *pkth, void *arg) +{ + struct h263_strm h263_strm; + struct h263_hdr h263_hdr; + size_t pos; + int err; + + /* Decode bit-stream header, used by packetizer */ + err = h263_strm_decode(&h263_strm, mb); + if (err) + return err; + + h263_hdr_copy_strm(&h263_hdr, &h263_strm); + + st->mb_frag->pos = st->mb_frag->end = 0; + err = h263_hdr_encode(&h263_hdr, st->mb_frag); + pos = st->mb_frag->pos; + + /* Assemble frame into smaller packets */ + while (!err) { + size_t sz, left = mbuf_get_left(mb); + bool last = (left < st->encprm.pktsize); + if (!left) + break; + + sz = last ? left : st->encprm.pktsize; + + st->mb_frag->pos = st->mb_frag->end = pos; + err = mbuf_write_mem(st->mb_frag, mbuf_buf(mb), sz); + if (err) + break; + + st->mb_frag->pos = 0; + + err = pkth(last, NULL, 0, mbuf_buf(st->mb_frag), + mbuf_get_left(st->mb_frag), arg); + + mbuf_advance(mb, sz); + } + + return err; +} + + +#ifdef USE_X264 +static int open_encoder_x264(struct videnc_state *st, struct videnc_param *prm, + const struct vidsz *size) +{ + x264_param_t xprm; + + x264_param_default(&xprm); + +#if X264_BUILD >= 87 + x264_param_apply_profile(&xprm, "baseline"); +#endif + + xprm.i_level_idc = h264_level_idc; + xprm.i_width = size->w; + xprm.i_height = size->h; + xprm.i_csp = X264_CSP_I420; + xprm.i_fps_num = prm->fps; + xprm.i_fps_den = 1; + xprm.rc.i_bitrate = prm->bitrate / 1024; /* kbit/s */ + xprm.rc.i_rc_method = X264_RC_CQP; + xprm.i_log_level = X264_LOG_WARNING; + + /* ultrafast preset */ + xprm.i_frame_reference = 1; + xprm.i_scenecut_threshold = 0; + xprm.b_deblocking_filter = 0; + xprm.b_cabac = 0; + xprm.i_bframe = 0; + xprm.analyse.intra = 0; + xprm.analyse.inter = 0; + xprm.analyse.b_transform_8x8 = 0; + xprm.analyse.i_me_method = X264_ME_DIA; + xprm.analyse.i_subpel_refine = 0; +#if X264_BUILD >= 59 + xprm.rc.i_aq_mode = 0; +#endif + xprm.analyse.b_mixed_references = 0; + xprm.analyse.i_trellis = 0; +#if X264_BUILD >= 63 + xprm.i_bframe_adaptive = X264_B_ADAPT_NONE; +#endif +#if X264_BUILD >= 70 + xprm.rc.b_mb_tree = 0; +#endif + + /* slice-based threading (--tune=zerolatency) */ +#if X264_BUILD >= 80 + xprm.rc.i_lookahead = 0; + xprm.i_sync_lookahead = 0; + xprm.i_bframe = 0; +#endif + + /* put SPS/PPS before each keyframe */ + xprm.b_repeat_headers = 1; + +#if X264_BUILD >= 82 + /* needed for x264_encoder_intra_refresh() */ + xprm.b_intra_refresh = 1; +#endif + + if (st->x264) + x264_encoder_close(st->x264); + + st->x264 = x264_encoder_open(&xprm); + if (!st->x264) { + warning("avcodec: x264_encoder_open() failed\n"); + return ENOENT; + } + + st->encsize = *size; + + return 0; +} +#endif + + +int encode_update(struct videnc_state **vesp, const struct vidcodec *vc, + struct videnc_param *prm, const char *fmtp) +{ + struct videnc_state *st; + int err = 0; + + if (!vesp || !vc || !prm) + return EINVAL; + + if (*vesp) + return 0; + + st = mem_zalloc(sizeof(*st), destructor); + if (!st) + return ENOMEM; + + st->encprm = *prm; + + st->codec_id = avcodec_resolve_codecid(vc->name); + if (st->codec_id == CODEC_ID_NONE) { + err = EINVAL; + goto out; + } + + st->mb = mbuf_alloc(FF_MIN_BUFFER_SIZE * 20); + st->mb_frag = mbuf_alloc(1024); + if (!st->mb || !st->mb_frag) { + err = ENOMEM; + goto out; + } + + st->sz_max = st->mb->size; + + if (st->codec_id == CODEC_ID_H264) { +#ifndef USE_X264 + err = init_encoder(st); +#endif + } + else + err = init_encoder(st); + if (err) { + warning("avcodec: %s: could not init encoder\n", vc->name); + goto out; + } + + if (str_isset(fmtp)) { + struct pl sdp_fmtp; + + pl_set_str(&sdp_fmtp, fmtp); + + fmt_param_apply(&sdp_fmtp, param_handler, st); + } + + debug("avcodec: video encoder %s: %d fps, %d bit/s, pktsize=%u\n", + vc->name, prm->fps, prm->bitrate, prm->pktsize); + + out: + if (err) + mem_deref(st); + else + *vesp = st; + + return err; +} + + +#ifdef USE_X264 +int encode_x264(struct videnc_state *st, bool update, + const struct vidframe *frame, + videnc_packet_h *pkth, void *arg) +{ + x264_picture_t pic_in, pic_out; + x264_nal_t *nal; + int i_nal; + int i, err, ret; + + if (!st->x264 || !vidsz_cmp(&st->encsize, &frame->size)) { + + err = open_encoder_x264(st, &st->encprm, &frame->size); + if (err) + return err; + } + + if (update) { +#if X264_BUILD >= 95 + x264_encoder_intra_refresh(st->x264); +#endif + debug("avcodec: x264 picture update\n"); + } + + x264_picture_init(&pic_in); + + pic_in.i_type = update ? X264_TYPE_IDR : X264_TYPE_AUTO; + pic_in.i_qpplus1 = 0; + pic_in.i_pts = ++st->pts; + + pic_in.img.i_csp = X264_CSP_I420; + pic_in.img.i_plane = 3; + for (i=0; i<3; i++) { + pic_in.img.i_stride[i] = frame->linesize[i]; + pic_in.img.plane[i] = frame->data[i]; + } + + ret = x264_encoder_encode(st->x264, &nal, &i_nal, &pic_in, &pic_out); + if (ret < 0) { + fprintf(stderr, "x264 [error]: x264_encoder_encode failed\n"); + } + if (i_nal == 0) + return 0; + + err = 0; + for (i=0; i<i_nal && !err; i++) { + const uint8_t hdr = nal[i].i_ref_idc<<5 | nal[i].i_type<<0; + int offset = 0; + +#if X264_BUILD >= 76 + const uint8_t *p = nal[i].p_payload; + + /* Find the NAL Escape code [00 00 01] */ + if (nal[i].i_payload > 4 && p[0] == 0x00 && p[1] == 0x00) { + if (p[2] == 0x00 && p[3] == 0x01) + offset = 4 + 1; + else if (p[2] == 0x01) + offset = 3 + 1; + } +#endif + + /* skip Supplemental Enhancement Information (SEI) */ + if (nal[i].i_type == H264_NAL_SEI) + continue; + + err = h264_nal_send(true, true, (i+1)==i_nal, hdr, + nal[i].p_payload + offset, + nal[i].i_payload - offset, + st->encprm.pktsize, pkth, arg); + } + + return err; +} +#endif + + +int encode(struct videnc_state *st, bool update, const struct vidframe *frame, + videnc_packet_h *pkth, void *arg) +{ + int i, err, ret; + + if (!st || !frame || !pkth) + return EINVAL; + + if (!st->ctx || !vidsz_cmp(&st->encsize, &frame->size)) { + + err = open_encoder(st, &st->encprm, &frame->size); + if (err) { + warning("avcodec: open_encoder: %m\n", err); + return err; + } + } + + for (i=0; i<4; i++) { + st->pict->data[i] = frame->data[i]; + st->pict->linesize[i] = frame->linesize[i]; + } + st->pict->pts = st->pts++; + if (update) { + debug("avcodec: encoder picture update\n"); + st->pict->key_frame = 1; +#ifdef FF_I_TYPE + st->pict->pict_type = FF_I_TYPE; /* Infra Frame */ +#else + st->pict->pict_type = AV_PICTURE_TYPE_I; +#endif + } + else { + st->pict->key_frame = 0; + st->pict->pict_type = 0; + } + + mbuf_rewind(st->mb); + +#if LIBAVCODEC_VERSION_INT >= ((54<<16)+(1<<8)+0) + do { + AVPacket avpkt; + int got_packet; + + av_init_packet(&avpkt); + + avpkt.data = st->mb->buf; + avpkt.size = (int)st->mb->size; + + ret = avcodec_encode_video2(st->ctx, &avpkt, + st->pict, &got_packet); + if (ret < 0) + return EBADMSG; + if (!got_packet) + return 0; + + mbuf_set_end(st->mb, avpkt.size); + + } while (0); +#else + ret = avcodec_encode_video(st->ctx, st->mb->buf, + (int)st->mb->size, st->pict); + if (ret < 0 ) + return EBADMSG; + + /* todo: figure out proper buffer size */ + if (ret > (int)st->sz_max) { + debug("avcodec: grow encode buffer %u --> %d\n", + st->sz_max, ret); + st->sz_max = ret; + } + + mbuf_set_end(st->mb, ret); +#endif + + switch (st->codec_id) { + + case CODEC_ID_H263: + err = h263_packetize(st, st->mb, pkth, arg); + break; + + case CODEC_ID_H264: + err = h264_packetize(st->mb, st->encprm.pktsize, pkth, arg); + break; + + case CODEC_ID_MPEG4: + err = general_packetize(st->mb, st->encprm.pktsize, pkth, arg); + break; + + default: + err = EPROTO; + break; + } + + return err; +} diff --git a/modules/avcodec/h263.c b/modules/avcodec/h263.c new file mode 100644 index 0000000..7e29ecd --- /dev/null +++ b/modules/avcodec/h263.c @@ -0,0 +1,176 @@ +/** + * @file h263.c H.263 video codec (RFC 4629) + * + * Copyright (C) 2010 Creytiv.com + */ +#include <re.h> +#include <rem.h> +#include <baresip.h> +#include <libavcodec/avcodec.h> +#ifdef USE_X264 +#include <x264.h> +#endif +#include "h26x.h" +#include "avcodec.h" + + +int h263_hdr_encode(const struct h263_hdr *hdr, struct mbuf *mb) +{ + uint32_t v; /* host byte order */ + + v = hdr->f<<31 | hdr->p<<30 | hdr->sbit<<27 | hdr->ebit<<24; + v |= hdr->src<<21 | hdr->i<<20 | hdr->u<<19 | hdr->s<<18 | hdr->a<<17; + v |= hdr->r<<13 | hdr->dbq<<11 | hdr->trb<<8 | hdr->tr<<0; + + return mbuf_write_u32(mb, htonl(v)); +} + + +enum h263_mode h263_hdr_mode(const struct h263_hdr *hdr) +{ + if (!hdr->f) { + return H263_MODE_A; + } + else { + if (!hdr->p) + return H263_MODE_B; + else + return H263_MODE_C; + } +} + + +int h263_hdr_decode(struct h263_hdr *hdr, struct mbuf *mb) +{ + uint32_t v; + + if (!hdr) + return EINVAL; + if (mbuf_get_left(mb) < H263_HDR_SIZE_MODEA) + return EBADMSG; + + v = ntohl(mbuf_read_u32(mb)); + + /* Common */ + hdr->f = v>>31 & 0x1; + hdr->p = v>>30 & 0x1; + hdr->sbit = v>>27 & 0x7; + hdr->ebit = v>>24 & 0x7; + hdr->src = v>>21 & 0x7; + + switch (h263_hdr_mode(hdr)) { + + case H263_MODE_A: + hdr->i = v>>20 & 0x1; + hdr->u = v>>19 & 0x1; + hdr->s = v>>18 & 0x1; + hdr->a = v>>17 & 0x1; + hdr->r = v>>13 & 0xf; + hdr->dbq = v>>11 & 0x3; + hdr->trb = v>>8 & 0x7; + hdr->tr = v>>0 & 0xff; + break; + + case H263_MODE_B: + hdr->quant = v>>16 & 0x1f; + hdr->gobn = v>>11 & 0x1f; + hdr->mba = v>>2 & 0x1ff; + + if (mbuf_get_left(mb) < 4) + return EBADMSG; + + v = ntohl(mbuf_read_u32(mb)); + + hdr->i = v>>31 & 0x1; + hdr->u = v>>30 & 0x1; + hdr->s = v>>29 & 0x1; + hdr->a = v>>28 & 0x1; + hdr->hmv1 = v>>21 & 0x7f; + hdr->vmv1 = v>>14 & 0x7f; + hdr->hmv2 = v>>7 & 0x7f; + hdr->vmv2 = v>>0 & 0x7f; + break; + + case H263_MODE_C: + /* NOTE: Mode C is optional, only parts decoded */ + if (mbuf_get_left(mb) < 8) + return EBADMSG; + + v = ntohl(mbuf_read_u32(mb)); + hdr->i = v>>31 & 0x1; + hdr->u = v>>30 & 0x1; + hdr->s = v>>29 & 0x1; + hdr->a = v>>28 & 0x1; + + (void)mbuf_read_u32(mb); /* ignore */ + break; + } + + return 0; +} + + +/** Find PSC (Picture Start Code) in bit-stream */ +const uint8_t *h263_strm_find_psc(const uint8_t *p, uint32_t size) +{ + const uint8_t *end = p + size - 1; + + for (; p < end; p++) { + if (p[0] == 0x00 && p[1] == 0x00) + return p; + } + + return NULL; +} + + +int h263_strm_decode(struct h263_strm *s, struct mbuf *mb) +{ + const uint8_t *p; + + if (mbuf_get_left(mb) < 6) + return EINVAL; + + p = mbuf_buf(mb); + + s->psc[0] = p[0]; + s->psc[1] = p[1]; + + s->temp_ref = (p[2]<<6 & 0xc0) | (p[3]>>2 & 0x3f); + + s->split_scr = p[4]>>7 & 0x1; + s->doc_camera = p[4]>>6 & 0x1; + s->pic_frz_rel = p[4]>>5 & 0x1; + s->src_fmt = p[4]>>2 & 0x7; + s->pic_type = p[4]>>1 & 0x1; + s->umv = p[4]>>0 & 0x1; + + s->sac = p[5]>>7 & 0x1; + s->apm = p[5]>>6 & 0x1; + s->pb = p[5]>>5 & 0x1; + s->pquant = p[5]>>0 & 0x1f; + + s->cpm = p[6]>>7 & 0x1; + s->pei = p[6]>>6 & 0x1; + + return 0; +} + + +/** Copy H.263 bit-stream to H.263 RTP payload header */ +void h263_hdr_copy_strm(struct h263_hdr *hdr, const struct h263_strm *s) +{ + hdr->f = 0; /* Mode A */ + hdr->p = 0; + hdr->sbit = 0; + hdr->ebit = 0; + hdr->src = s->src_fmt; + hdr->i = s->pic_type; + hdr->u = s->umv; + hdr->s = s->sac; + hdr->a = s->apm; + hdr->r = 0; + hdr->dbq = 0; /* No PB-frames */ + hdr->trb = 0; /* No PB-frames */ + hdr->tr = s->temp_ref; +} diff --git a/modules/avcodec/h264.c b/modules/avcodec/h264.c new file mode 100644 index 0000000..4c2aa59 --- /dev/null +++ b/modules/avcodec/h264.c @@ -0,0 +1,188 @@ +/** + * @file avcodec/h264.c H.264 video codec (RFC 3984) + * + * Copyright (C) 2010 Creytiv.com + */ +#include <string.h> +#include <re.h> +#include <rem.h> +#include <baresip.h> +#include <libavcodec/avcodec.h> +#ifdef USE_X264 +#include <x264.h> +#endif +#include "h26x.h" +#include "avcodec.h" + + +const uint8_t h264_level_idc = 0x0c; + + +int h264_hdr_encode(const struct h264_hdr *hdr, struct mbuf *mb) +{ + uint8_t v; + + v = hdr->f<<7 | hdr->nri<<5 | hdr->type<<0; + + return mbuf_write_u8(mb, v); +} + + +int h264_hdr_decode(struct h264_hdr *hdr, struct mbuf *mb) +{ + uint8_t v; + + if (mbuf_get_left(mb) < 1) + return ENOENT; + + v = mbuf_read_u8(mb); + + hdr->f = v>>7 & 0x1; + hdr->nri = v>>5 & 0x3; + hdr->type = v>>0 & 0x1f; + + return 0; +} + + +int fu_hdr_encode(const struct fu *fu, struct mbuf *mb) +{ + uint8_t v = fu->s<<7 | fu->s<<6 | fu->r<<5 | fu->type; + return mbuf_write_u8(mb, v); +} + + +int fu_hdr_decode(struct fu *fu, struct mbuf *mb) +{ + uint8_t v; + + if (mbuf_get_left(mb) < 1) + return ENOENT; + + v = mbuf_read_u8(mb); + + fu->s = v>>7 & 0x1; + fu->e = v>>6 & 0x1; + fu->r = v>>5 & 0x1; + fu->type = v>>0 & 0x1f; + + return 0; +} + + +/* + * Find the NAL start sequence in a H.264 byte stream + * + * @note: copied from ffmpeg source + */ +const uint8_t *h264_find_startcode(const uint8_t *p, const uint8_t *end) +{ + const uint8_t *a = p + 4 - ((long)p & 3); + + for (end -= 3; p < a && p < end; p++ ) { + if (p[0] == 0 && p[1] == 0 && p[2] == 1) + return p; + } + + for (end -= 3; p < end; p += 4) { + uint32_t x = *(const uint32_t*)(void *)p; + if ( (x - 0x01010101) & (~x) & 0x80808080 ) { + if (p[1] == 0 ) { + if ( p[0] == 0 && p[2] == 1 ) + return p; + if ( p[2] == 0 && p[3] == 1 ) + return p+1; + } + if ( p[3] == 0 ) { + if ( p[2] == 0 && p[4] == 1 ) + return p+2; + if ( p[4] == 0 && p[5] == 1 ) + return p+3; + } + } + } + + for (end += 3; p < end; p++) { + if (p[0] == 0 && p[1] == 0 && p[2] == 1) + return p; + } + + return end + 3; +} + + +static int rtp_send_data(const uint8_t *hdr, size_t hdr_sz, + const uint8_t *buf, size_t sz, bool eof, + videnc_packet_h *pkth, void *arg) +{ + return pkth(eof, hdr, hdr_sz, buf, sz, arg); +} + + +int h264_nal_send(bool first, bool last, + bool marker, uint32_t ihdr, const uint8_t *buf, + size_t size, size_t maxsz, + videnc_packet_h *pkth, void *arg) +{ + uint8_t hdr = (uint8_t)ihdr; + int err = 0; + + if (first && last && size <= maxsz) { + err = rtp_send_data(&hdr, 1, buf, size, marker, + pkth, arg); + } + else { + uint8_t fu_hdr[2]; + const uint8_t type = hdr & 0x1f; + const uint8_t nri = hdr & 0x60; + const size_t sz = maxsz - 2; + + fu_hdr[0] = nri | H264_NAL_FU_A; + fu_hdr[1] = first ? (1<<7 | type) : type; + + while (size > sz) { + err |= rtp_send_data(fu_hdr, 2, buf, sz, false, + pkth, arg); + buf += sz; + size -= sz; + fu_hdr[1] &= ~(1 << 7); + } + + if (last) + fu_hdr[1] |= 1<<6; /* end bit */ + + err |= rtp_send_data(fu_hdr, 2, buf, size, marker && last, + pkth, arg); + } + + return err; +} + + +int h264_packetize(struct mbuf *mb, size_t pktsize, + videnc_packet_h *pkth, void *arg) +{ + const uint8_t *start = mb->buf; + const uint8_t *end = start + mb->end; + const uint8_t *r; + int err = 0; + + r = h264_find_startcode(mb->buf, end); + + while (r < end) { + const uint8_t *r1; + + /* skip zeros */ + while (!*(r++)) + ; + + r1 = h264_find_startcode(r, end); + + err |= h264_nal_send(true, true, (r1 >= end), r[0], + r+1, r1-r-1, pktsize, + pkth, arg); + r = r1; + } + + return err; +} diff --git a/modules/avcodec/h26x.h b/modules/avcodec/h26x.h new file mode 100644 index 0000000..7a21696 --- /dev/null +++ b/modules/avcodec/h26x.h @@ -0,0 +1,165 @@ +/** + * @file h26x.h Interface to H.26x video codecs + * + * Copyright (C) 2010 Creytiv.com + */ + + +/* + * H.263 + */ + + +enum h263_mode { + H263_MODE_A, + H263_MODE_B, + H263_MODE_C +}; + +enum { + H263_HDR_SIZE_MODEA = 4, + H263_HDR_SIZE_MODEB = 8, + H263_HDR_SIZE_MODEC = 12 +}; + +/** H.263 picture size format */ +enum h263_fmt { + H263_FMT_SQCIF = 1, /**< 128 x 96 */ + H263_FMT_QCIF = 2, /**< 176 x 144 */ + H263_FMT_CIF = 3, /**< 352 x 288 */ + H263_FMT_4CIF = 4, /**< 704 x 576 */ + H263_FMT_16CIF = 5, /**< 1408 x 1152 */ + H263_FMT_OTHER = 7, +}; + +/** + * H.263 Header defined in RFC 2190 + */ +struct h263_hdr { + + /* common */ + unsigned f:1; /**< 1 bit - Flag; 0=mode A, 1=mode B/C */ + unsigned p:1; /**< 1 bit - PB-frames, 0=mode B, 1=mode C */ + unsigned sbit:3; /**< 3 bits - Start Bit Position (SBIT) */ + unsigned ebit:3; /**< 3 bits - End Bit Position (EBIT) */ + unsigned src:3; /**< 3 bits - Source format */ + + /* mode A */ + unsigned i:1; /**< 1 bit - 0=intra-coded, 1=inter-coded */ + unsigned u:1; /**< 1 bit - Unrestricted Motion Vector */ + unsigned s:1; /**< 1 bit - Syntax-based Arithmetic Coding */ + unsigned a:1; /**< 1 bit - Advanced Prediction option */ + unsigned r:4; /**< 4 bits - Reserved (zero) */ + unsigned dbq:2; /**< 2 bits - DBQUANT */ + unsigned trb:3; /**< 3 bits - Temporal Reference for B-frame */ + unsigned tr:8; /**< 8 bits - Temporal Reference for P-frame */ + + /* mode B */ + unsigned quant:5; //=0 for GOB header + unsigned gobn:5; // gob number + unsigned mba:9; // address + unsigned hmv1:7; // horizontal motion vector + unsigned vmv1:7; // vertical motion vector + unsigned hmv2:7; + unsigned vmv2:7; + + +}; + +enum {I_FRAME=0, P_FRAME=1}; + +/** H.263 bit-stream header */ +struct h263_strm { + uint8_t psc[2]; /**< Picture Start Code (PSC) */ + + uint8_t temp_ref; /**< Temporal Reference */ + unsigned split_scr:1; /**< Split Screen Indicator */ + unsigned doc_camera:1; /**< Document Camera Indicator */ + unsigned pic_frz_rel:1; /**< Full Picture Freeze Release */ + unsigned src_fmt:3; /**< Source Format. 3=CIF */ + unsigned pic_type:1; /**< Picture Coding Type. 0=I, 1=P */ + unsigned umv:1; /**< Unrestricted Motion Vector mode */ + unsigned sac:1; /**< Syntax-based Arithmetic Coding */ + unsigned apm:1; /**< Advanced Prediction mode */ + unsigned pb:1; /**< PB-frames mode */ + unsigned pquant:5; /**< Quantizer Information */ + unsigned cpm:1; /**< Continuous Presence Multipoint */ + unsigned pei:1; /**< Extra Insertion Information */ + /* H.263 bit-stream ... */ +}; + +int h263_hdr_encode(const struct h263_hdr *hdr, struct mbuf *mb); +int h263_hdr_decode(struct h263_hdr *hdr, struct mbuf *mb); +enum h263_mode h263_hdr_mode(const struct h263_hdr *hdr); + +const uint8_t *h263_strm_find_psc(const uint8_t *p, uint32_t size); +int h263_strm_decode(struct h263_strm *s, struct mbuf *mb); +void h263_hdr_copy_strm(struct h263_hdr *hdr, const struct h263_strm *s); + + +/* + * H.264 + */ + + +/** NAL unit types (RFC 3984, Table 1) */ +enum { + H264_NAL_UNKNOWN = 0, + /* 1-23 NAL unit Single NAL unit packet per H.264 */ + H264_NAL_SLICE = 1, + H264_NAL_DPA = 2, + H264_NAL_DPB = 3, + H264_NAL_DPC = 4, + H264_NAL_IDR_SLICE = 5, + H264_NAL_SEI = 6, + H264_NAL_SPS = 7, + H264_NAL_PPS = 8, + H264_NAL_AUD = 9, + H264_NAL_END_SEQUENCE = 10, + H264_NAL_END_STREAM = 11, + H264_NAL_FILLER_DATA = 12, + H264_NAL_SPS_EXT = 13, + H264_NAL_AUX_SLICE = 19, + + H264_NAL_STAP_A = 24, /**< Single-time aggregation packet */ + H264_NAL_STAP_B = 25, /**< Single-time aggregation packet */ + H264_NAL_MTAP16 = 26, /**< Multi-time aggregation packet */ + H264_NAL_MTAP24 = 27, /**< Multi-time aggregation packet */ + H264_NAL_FU_A = 28, /**< Fragmentation unit */ + H264_NAL_FU_B = 29, /**< Fragmentation unit */ +}; + +/** + * H.264 Header defined in RFC 3984 + * + * <pre> + +---------------+ + |0|1|2|3|4|5|6|7| + +-+-+-+-+-+-+-+-+ + |F|NRI| Type | + +---------------+ + * </pre> + */ +struct h264_hdr { + unsigned f:1; /**< 1 bit - Forbidden zero bit (must be 0) */ + unsigned nri:2; /**< 2 bits - nal_ref_idc */ + unsigned type:5; /**< 5 bits - nal_unit_type */ +}; + +int h264_hdr_encode(const struct h264_hdr *hdr, struct mbuf *mb); +int h264_hdr_decode(struct h264_hdr *hdr, struct mbuf *mb); + +/** Fragmentation Unit header */ +struct fu { + unsigned s:1; /**< Start bit */ + unsigned e:1; /**< End bit */ + unsigned r:1; /**< The Reserved bit MUST be equal to 0 */ + unsigned type:5; /**< The NAL unit payload type */ +}; + +int fu_hdr_encode(const struct fu *fu, struct mbuf *mb); +int fu_hdr_decode(struct fu *fu, struct mbuf *mb); + +const uint8_t *h264_find_startcode(const uint8_t *p, const uint8_t *end); + +int h264_decode_sprop_params(AVCodecContext *codec, struct pl *pl); diff --git a/modules/avcodec/module.mk b/modules/avcodec/module.mk new file mode 100644 index 0000000..b209a57 --- /dev/null +++ b/modules/avcodec/module.mk @@ -0,0 +1,20 @@ +# +# module.mk +# +# Copyright (C) 2010 Creytiv.com +# + +USE_X264 := $(shell [ -f $(SYSROOT)/include/x264.h ] || \ + [ -f $(SYSROOT)/local/include/x264.h ] || \ + [ -f $(SYSROOT_ALT)/include/x264.h ] && echo "yes") + +MOD := avcodec +$(MOD)_SRCS += avcodec.c h263.c h264.c encode.c decode.c +$(MOD)_LFLAGS += -lavcodec -lavutil +CFLAGS += -I/usr/include/ffmpeg +ifneq ($(USE_X264),) +CFLAGS += -DUSE_X264 +$(MOD)_LFLAGS += -lx264 +endif + +include mk/mod.mk |