diff options
author | rizzo <rizzo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-12-26 10:14:11 +0000 |
---|---|---|
committer | rizzo <rizzo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2007-12-26 10:14:11 +0000 |
commit | 7f64f70d63ce1451e8984561417ca232e2235ea6 (patch) | |
tree | 64629a22170c7335107f601d357e16d103339eab /channels/vcodecs.c | |
parent | 68d4a88f5f76fe1ec944c72bb905fd004e04f25c (diff) |
Split console_video.c so that video codecs and gui functions
are in separate files (still #include'd because of tangling in the data
structures, but this is going to be cleaned up).
The video grabbing functions still need to be moved to a separate file.
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@94774 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/vcodecs.c')
-rw-r--r-- | channels/vcodecs.c | 1009 |
1 files changed, 1009 insertions, 0 deletions
diff --git a/channels/vcodecs.c b/channels/vcodecs.c new file mode 100644 index 000000000..197726eb9 --- /dev/null +++ b/channels/vcodecs.c @@ -0,0 +1,1009 @@ +/* + * Video codecs support for console_video.c + * $Revision$ + */ + +/* + * Each codec is defined by a number of callbacks + */ +/*! \brief initialize the encoder */ +typedef int (*encoder_init_f)(AVCodecContext *v); + +/*! \brief actually call the encoder */ +typedef int (*encoder_encode_f)(struct video_out_desc *v); + +/*! \brief encapsulate the bistream in RTP frames */ +typedef struct ast_frame *(*encoder_encap_f)(struct video_out_desc *out, + struct ast_frame **tail); + +/*! \brief inizialize the decoder */ +typedef int (*decoder_init_f)(AVCodecContext *enc_ctx); + +/*! \brief extract the bitstream from RTP frames and store in the fbuf. + * return 0 if ok, 1 on error + */ +typedef int (*decoder_decap_f)(struct fbuf_t *b, uint8_t *data, int len); + +/*! \brief actually call the decoder */ +typedef int (*decoder_decode_f)(struct video_in_desc *v, struct fbuf_t *b); + +struct video_codec_desc { + const char *name; /* format name */ + int format; /* AST_FORMAT_* */ + encoder_init_f enc_init; + encoder_encap_f enc_encap; + encoder_encode_f enc_run; + decoder_init_f dec_init; + decoder_decap_f dec_decap; + decoder_decode_f dec_run; +}; + +#ifdef debugging_only + +/* some debugging code to check the bitstream: + * declare a bit buffer, initialize it, and fetch data from it. + */ +struct bitbuf { + const uint8_t *base; + int bitsize; /* total size in bits */ + int ofs; /* next bit to read */ +}; + +static struct bitbuf bitbuf_init(const uint8_t *base, int bitsize, int start_ofs) +{ + struct bitbuf a; + a.base = base; + a.bitsize = bitsize; + a.ofs = start_ofs; + return a; +} + +static int bitbuf_left(struct bitbuf *b) +{ + return b->bitsize - b->ofs; +} + +static uint32_t getbits(struct bitbuf *b, int n) +{ + int i, ofs; + const uint8_t *d; + uint8_t mask; + uint32_t retval = 0; + if (n> 31) { + ast_log(LOG_WARNING, "too many bits %d, max 32\n", n); + return 0; + } + if (n + b->ofs > b->bitsize) { + ast_log(LOG_WARNING, "bitbuf overflow %d of %d\n", n + b->ofs, b->bitsize); + n = b->bitsize - b->ofs; + } + ofs = 7 - b->ofs % 8; /* start from msb */ + mask = 1 << ofs; + d = b->base + b->ofs / 8; /* current byte */ + for (i=0 ; i < n; i++) { + retval += retval + (*d & mask ? 1 : 0); /* shift in new byte */ + b->ofs++; + mask >>= 1; + if (mask == 0) { + d++; + mask = 0x80; + } + } + return retval; +} + +static void check_h261(struct fbuf_t *b) +{ + struct bitbuf a = bitbuf_init(b->data, b->used * 8, 0); + uint32_t x, y; + + x = getbits(&a, 20); /* PSC, 0000 0000 0000 0001 0000 */ + if (x != 0x10) { + ast_log(LOG_WARNING, "bad PSC 0x%x\n", x); + return; + } + x = getbits(&a, 5); /* temporal reference */ + y = getbits(&a, 6); /* ptype */ + if (0) + ast_log(LOG_WARNING, "size %d TR %d PTY spl %d doc %d freeze %d %sCIF hi %d\n", + b->used, + x, + (y & 0x20) ? 1 : 0, + (y & 0x10) ? 1 : 0, + (y & 0x8) ? 1 : 0, + (y & 0x4) ? "" : "Q", + (y & 0x2) ? 1:0); + while ( (x = getbits(&a, 1)) == 1) + ast_log(LOG_WARNING, "PSPARE 0x%x\n", getbits(&a, 8)); + // ast_log(LOG_WARNING, "PSPARE 0 - start GOB LAYER\n"); + while ( (x = bitbuf_left(&a)) > 0) { + // ast_log(LOG_WARNING, "GBSC %d bits left\n", x); + x = getbits(&a, 16); /* GBSC 0000 0000 0000 0001 */ + if (x != 0x1) { + ast_log(LOG_WARNING, "bad GBSC 0x%x\n", x); + break; + } + x = getbits(&a, 4); /* group number */ + y = getbits(&a, 5); /* gquant */ + if (x == 0) { + ast_log(LOG_WARNING, " bad GN %d\n", x); + break; + } + while ( (x = getbits(&a, 1)) == 1) + ast_log(LOG_WARNING, "GSPARE 0x%x\n", getbits(&a, 8)); + while ( (x = bitbuf_left(&a)) > 0) { /* MB layer */ + break; + } + } +} + +void dump_buf(struct fbuf_t *b); +void dump_buf(struct fbuf_t *b) +{ + int i, x, last2lines; + char buf[80]; + + last2lines = (b->used - 16) & ~0xf; + ast_log(LOG_WARNING, "buf size %d of %d\n", b->used, b->size); + for (i = 0; i < b->used; i++) { + x = i & 0xf; + if ( x == 0) { /* new line */ + if (i != 0) + ast_log(LOG_WARNING, "%s\n", buf); + bzero(buf, sizeof(buf)); + sprintf(buf, "%04x: ", i); + } + sprintf(buf + 6 + x*3, "%02x ", b->data[i]); + if (i > 31 && i < last2lines) + i = last2lines - 1; + } + if (buf[0]) + ast_log(LOG_WARNING, "%s\n", buf); +} +#endif /* debugging_only */ +/* + * Here starts the glue code for the various supported video codecs. + * For each of them, we need to provide routines for initialization, + * calling the encoder, encapsulating the bitstream in ast_frames, + * extracting payload from ast_frames, and calling the decoder. + */ + +/*--- h263+ support --- */ + +/*! \brief initialization of h263p */ +static int h263p_enc_init(AVCodecContext *enc_ctx) +{ + /* modes supported are + - Unrestricted Motion Vector (annex D) + - Advanced Prediction (annex F) + - Advanced Intra Coding (annex I) + - Deblocking Filter (annex J) + - Slice Structure (annex K) + - Alternative Inter VLC (annex S) + - Modified Quantization (annex T) + */ + enc_ctx->flags |=CODEC_FLAG_H263P_UMV; /* annex D */ + enc_ctx->flags |=CODEC_FLAG_AC_PRED; /* annex f ? */ + enc_ctx->flags |=CODEC_FLAG_H263P_SLICE_STRUCT; /* annex k */ + enc_ctx->flags |= CODEC_FLAG_H263P_AIC; /* annex I */ + + return 0; +} + + +/* + * Create RTP/H.263 fragments to avoid IP fragmentation. We fragment on a + * PSC or a GBSC, but if we don't find a suitable place just break somewhere. + * Everything is byte-aligned. + */ +static struct ast_frame *h263p_encap(struct video_out_desc *out, + struct ast_frame **tail) +{ + struct ast_frame *cur = NULL, *first = NULL; + uint8_t *d = out->enc_out.data; + int len = out->enc_out.used; + int l = len; /* size of the current fragment. If 0, must look for a psc */ + + for (;len > 0; len -= l, d += l) { + uint8_t *data; + struct ast_frame *f; + int i, h; + + if (len >= 3 && d[0] == 0 && d[1] == 0 && d[2] >= 0x80) { + /* we are starting a new block, so look for a PSC. */ + for (i = 3; i < len - 3; i++) { + if (d[i] == 0 && d[i+1] == 0 && d[i+2] >= 0x80) { + l = i; + break; + } + } + } + if (l > out->mtu || l > len) { /* psc not found, split */ + l = MIN(len, out->mtu); + } + if (l < 1 || l > out->mtu) { + ast_log(LOG_WARNING, "--- frame error l %d\n", l); + break; + } + + if (d[0] == 0 && d[1] == 0) { /* we start with a psc */ + h = 0; + } else { /* no psc, create a header */ + h = 2; + } + + f = create_video_frame(d, d+l, AST_FORMAT_H263_PLUS, h, cur); + if (!f) + break; + + data = f->data; + if (h == 0) { /* we start with a psc */ + data[0] |= 0x04; // set P == 1, and we are done + } else { /* no psc, create a header */ + data[0] = data[1] = 0; // P == 0 + } + + if (!cur) + first = f; + cur = f; + } + + if (cur) + cur->subclass |= 1; // RTP Marker + + *tail = cur; /* end of the list */ + return first; +} + +/*! \brief extract the bitstreem from the RTP payload. + * This is format dependent. + * For h263+, the format is defined in RFC 2429 + * and basically has a fixed 2-byte header as follows: + * 5 bits RR reserved, shall be 0 + * 1 bit P indicate a start/end condition, + * in which case the payload should be prepended + * by two zero-valued bytes. + * 1 bit V there is an additional VRC header after this header + * 6 bits PLEN length in bytes of extra picture header + * 3 bits PEBIT how many bits to be ignored in the last byte + * + * XXX the code below is not complete. + */ +static int h263p_decap(struct fbuf_t *b, uint8_t *data, int len) +{ + int PLEN; + + if (len < 2) { + ast_log(LOG_WARNING, "invalid framesize %d\n", len); + return 1; + } + PLEN = ( (data[0] & 1) << 5 ) | ( (data[1] & 0xf8) >> 3); + + if (PLEN > 0) { + data += PLEN; + len -= PLEN; + } + if (data[0] & 4) /* bit P */ + data[0] = data[1] = 0; + else { + data += 2; + len -= 2; + } + return fbuf_append(b, data, len, 0, 0); /* ignore trail bits */ +} + + +/* + * generic encoder, used by the various protocols supported here. + * We assume that the buffer is empty at the beginning. + */ +static int ffmpeg_encode(struct video_out_desc *v) +{ + struct fbuf_t *b = &v->enc_out; + int i; + + b->used = avcodec_encode_video(v->enc_ctx, b->data, b->size, v->enc_in_frame); + i = avcodec_encode_video(v->enc_ctx, b->data + b->used, b->size - b->used, NULL); /* delayed frames ? */ + if (i > 0) { + ast_log(LOG_WARNING, "have %d more bytes\n", i); + b->used += i; + } + return 0; +} + +/* + * Generic decoder, which is used by h263p, h263 and h261 as it simply + * invokes ffmpeg's decoder. + * av_parser_parse should merge a randomly chopped up stream into + * proper frames. After that, if we have a valid frame, we decode it + * until the entire frame is processed. + */ +static int ffmpeg_decode(struct video_in_desc *v, struct fbuf_t *b) +{ + uint8_t *src = b->data; + int srclen = b->used; + int full_frame = 0; + + if (srclen == 0) /* no data */ + return 0; + while (srclen) { + uint8_t *data; + int datalen, ret; + int len = av_parser_parse(v->parser, v->dec_ctx, &data, &datalen, src, srclen, 0, 0); + + src += len; + srclen -= len; + /* The parser might return something it cannot decode, so it skips + * the block returning no data + */ + if (data == NULL || datalen == 0) + continue; + ret = avcodec_decode_video(v->dec_ctx, v->d_frame, &full_frame, data, datalen); + if (full_frame == 1) /* full frame */ + break; + if (ret < 0) { + ast_log(LOG_NOTICE, "Error decoding\n"); + break; + } + } + if (srclen != 0) /* update b with leftover data */ + bcopy(src, b->data, srclen); + b->used = srclen; + b->ebit = 0; + return full_frame; +} + +static struct video_codec_desc h263p_codec = { + .name = "h263p", + .format = AST_FORMAT_H263_PLUS, + .enc_init = h263p_enc_init, + .enc_encap = h263p_encap, + .enc_run = ffmpeg_encode, + .dec_init = NULL, + .dec_decap = h263p_decap, + .dec_run = ffmpeg_decode +}; + +/*--- Plain h263 support --------*/ + +static int h263_enc_init(AVCodecContext *enc_ctx) +{ + /* XXX check whether these are supported */ + enc_ctx->flags |= CODEC_FLAG_H263P_UMV; + enc_ctx->flags |= CODEC_FLAG_H263P_AIC; + enc_ctx->flags |= CODEC_FLAG_H263P_SLICE_STRUCT; + enc_ctx->flags |= CODEC_FLAG_AC_PRED; + + return 0; +} + +/* + * h263 encapsulation is specified in RFC2190. There are three modes + * defined (A, B, C), with 4, 8 and 12 bytes of header, respectively. + * The header is made as follows + * 0.....................|.......................|.............|....31 + * F:1 P:1 SBIT:3 EBIT:3 SRC:3 I:1 U:1 S:1 A:1 R:4 DBQ:2 TRB:3 TR:8 + * FP = 0- mode A, (only one word of header) + * FP = 10 mode B, and also means this is an I or P frame + * FP = 11 mode C, and also means this is a PB frame. + * SBIT, EBIT nuber of bits to ignore at beginning (msbits) and end (lsbits) + * SRC bits 6,7,8 from the h263 PTYPE field + * I = 0 intra-coded, 1 = inter-coded (bit 9 from PTYPE) + * U = 1 for Unrestricted Motion Vector (bit 10 from PTYPE) + * S = 1 for Syntax Based Arith coding (bit 11 from PTYPE) + * A = 1 for Advanced Prediction (bit 12 from PTYPE) + * R = reserved, must be 0 + * DBQ = differential quantization, DBQUANT from h263, 0 unless we are using + * PB frames + * TRB = temporal reference for bframes, also 0 unless this is a PB frame + * TR = temporal reference for P frames, also 0 unless PB frame. + * + * Mode B and mode C description omitted. + * + * An RTP frame can start with a PSC 0000 0000 0000 0000 1000 0 + * or with a GBSC, which also has the first 17 bits as a PSC. + * Note - PSC are byte-aligned, GOB not necessarily. PSC start with + * PSC:22 0000 0000 0000 0000 1000 00 picture start code + * TR:8 .... .... temporal reference + * PTYPE:13 or more ptype... + * If we don't fragment a GOB SBIT and EBIT = 0. + * reference, 8 bit) + * + * The assumption below is that we start with a PSC. + */ +static struct ast_frame *h263_encap(struct video_out_desc *out, + struct ast_frame **tail) +{ + uint8_t *d = out->enc_out.data; + int start = 0, i, len = out->enc_out.used; + struct ast_frame *f, *cur = NULL, *first = NULL; + const int pheader_len = 4; /* Use RFC-2190 Mode A */ + uint8_t h263_hdr[12]; /* worst case, room for a type c header */ + uint8_t *h = h263_hdr; /* shorthand */ + +#define H263_MIN_LEN 6 + if (len < H263_MIN_LEN) /* unreasonably small */ + return NULL; + + bzero(h263_hdr, sizeof(h263_hdr)); + /* Now set the header bytes. Only type A by now, + * and h[0] = h[2] = h[3] = 0 by default. + * PTYPE starts 30 bits in the picture, so the first useful + * bit for us is bit 36 i.e. within d[4] (0 is the msbit). + * SRC = d[4] & 0x1c goes into data[1] & 0xe0 + * I = d[4] & 0x02 goes into data[1] & 0x10 + * U = d[4] & 0x01 goes into data[1] & 0x08 + * S = d[5] & 0x80 goes into data[1] & 0x04 + * A = d[5] & 0x40 goes into data[1] & 0x02 + * R = 0 goes into data[1] & 0x01 + * Optimizing it, we have + */ + h[1] = ( (d[4] & 0x1f) << 3 ) | /* SRC, I, U */ + ( (d[5] & 0xc0) >> 5 ); /* S, A, R */ + + /* now look for the next PSC or GOB header. First try to hit + * a '0' byte then look around for the 0000 0000 0000 0000 1 pattern + * which is both in the PSC and the GBSC. + */ + for (i = H263_MIN_LEN, start = 0; start < len; start = i, i += 3) { + //ast_log(LOG_WARNING, "search at %d of %d/%d\n", i, start, len); + for (; i < len ; i++) { + uint8_t x, rpos, lpos; + int rpos_i; /* index corresponding to rpos */ + if (d[i] != 0) /* cannot be in a GBSC */ + continue; + if (i > len - 1) + break; + x = d[i+1]; + if (x == 0) /* next is equally good */ + continue; + /* see if around us we can make 16 '0' bits for the GBSC. + * Look for the first bit set on the right, and then + * see if we have enough 0 on the left. + * We are guaranteed to end before rpos == 0 + */ + for (rpos = 0x80, rpos_i = 8; rpos; rpos >>= 1, rpos_i--) + if (x & rpos) /* found the '1' bit in GBSC */ + break; + x = d[i-1]; /* now look behind */ + for (lpos = rpos; lpos ; lpos >>= 1) + if (x & lpos) /* too early, not a GBSC */ + break; + if (lpos) /* as i said... */ + continue; + /* now we have a GBSC starting somewhere in d[i-1], + * but it might be not byte-aligned + */ + if (rpos == 0x80) { /* lucky case */ + i = i - 1; + } else { /* XXX to be completed */ + ast_log(LOG_WARNING, "unaligned GBSC 0x%x %d\n", + rpos, rpos_i); + } + break; + } + /* This frame is up to offset i (not inclusive). + * We do not split it yet even if larger than MTU. + */ + f = create_video_frame(d + start, d+i, AST_FORMAT_H263, + pheader_len, cur); + + if (!f) + break; + bcopy(h, f->data, 4); /* copy the h263 header */ + /* XXX to do: if not aligned, fix sbit and ebit, + * then move i back by 1 for the next frame + */ + if (!cur) + first = f; + cur = f; + } + + if (cur) + cur->subclass |= 1; // RTP Marker + + *tail = cur; + return first; +} + +/* XXX We only drop the header here, but maybe we need more. */ +static int h263_decap(struct fbuf_t *b, uint8_t *data, int len) +{ + if (len < 4) { + ast_log(LOG_WARNING, "invalid framesize %d\n", len); + return 1; /* error */ + } + + if ( (data[0] & 0x80) == 0) { + len -= 4; + data += 4; + } else { + ast_log(LOG_WARNING, "unsupported mode 0x%x\n", + data[0]); + return 1; + } + return fbuf_append(b, data, len, 0, 0); /* XXX no bit alignment support yet */ +} + +static struct video_codec_desc h263_codec = { + .name = "h263", + .format = AST_FORMAT_H263, + .enc_init = h263_enc_init, + .enc_encap = h263_encap, + .enc_run = ffmpeg_encode, + .dec_init = NULL, + .dec_decap = h263_decap, + .dec_run = ffmpeg_decode + +}; + +/*---- h261 support -----*/ +static int h261_enc_init(AVCodecContext *enc_ctx) +{ + /* It is important to set rtp_payload_size = 0, otherwise + * ffmpeg in h261 mode will produce output that it cannot parse. + * Also try to send I frames more frequently than with other codecs. + */ + enc_ctx->rtp_payload_size = 0; /* important - ffmpeg fails otherwise */ + + return 0; +} + +/* + * The encapsulation of H261 is defined in RFC4587 which obsoletes RFC2032 + * The bitstream is preceded by a 32-bit header word: + * SBIT:3 EBIT:3 I:1 V:1 GOBN:4 MBAP:5 QUANT:5 HMVD:5 VMVD:5 + * SBIT and EBIT are the bits to be ignored at beginning and end, + * I=1 if the stream has only INTRA frames - cannot change during the stream. + * V=0 if motion vector is not used. Cannot change. + * GOBN is the GOB number in effect at the start of packet, 0 if we + * start with a GOB header + * QUANT is the quantizer in effect, 0 if we start with GOB header + * HMVD reference horizontal motion vector. 10000 is forbidden + * VMVD reference vertical motion vector, as above. + * Packetization should occur at GOB boundaries, and if not possible + * with MacroBlock fragmentation. However it is likely that blocks + * are not bit-aligned so we must take care of this. + */ +static struct ast_frame *h261_encap(struct video_out_desc *out, + struct ast_frame **tail) +{ + uint8_t *d = out->enc_out.data; + int start = 0, i, len = out->enc_out.used; + struct ast_frame *f, *cur = NULL, *first = NULL; + const int pheader_len = 4; + uint8_t h261_hdr[4]; + uint8_t *h = h261_hdr; /* shorthand */ + int sbit = 0, ebit = 0; + +#define H261_MIN_LEN 10 + if (len < H261_MIN_LEN) /* unreasonably small */ + return NULL; + + bzero(h261_hdr, sizeof(h261_hdr)); + + /* Similar to the code in h263_encap, but the marker there is longer. + * Start a few bytes within the bitstream to avoid hitting the marker + * twice. Note we might access the buffer at len, but this is ok because + * the caller has it oversized. + */ + for (i = H261_MIN_LEN, start = 0; start < len - 1; start = i, i += 4) { +#if 0 /* test - disable packetization */ + i = len; /* wrong... */ +#else + int found = 0, found_ebit = 0; /* last GBSC position found */ + for (; i < len ; i++) { + uint8_t x, rpos, lpos; + if (d[i] != 0) /* cannot be in a GBSC */ + continue; + x = d[i+1]; + if (x == 0) /* next is equally good */ + continue; + /* See if around us we find 15 '0' bits for the GBSC. + * Look for the first bit set on the right, and then + * see if we have enough 0 on the left. + * We are guaranteed to end before rpos == 0 + */ + for (rpos = 0x80, ebit = 7; rpos; ebit--, rpos >>= 1) + if (x & rpos) /* found the '1' bit in GBSC */ + break; + x = d[i-1]; /* now look behind */ + for (lpos = (rpos >> 1); lpos ; lpos >>= 1) + if (x & lpos) /* too early, not a GBSC */ + break; + if (lpos) /* as i said... */ + continue; + /* now we have a GBSC starting somewhere in d[i-1], + * but it might be not byte-aligned. Just remember it. + */ + if (i - start > out->mtu) /* too large, stop now */ + break; + found_ebit = ebit; + found = i; + i += 4; /* continue forward */ + } + if (i >= len) { /* trim if we went too forward */ + i = len; + ebit = 0; /* hopefully... should ask the bitstream ? */ + } + if (i - start > out->mtu && found) { + /* use the previous GBSC, hope is within the mtu */ + i = found; + ebit = found_ebit; + } +#endif /* test */ + if (i - start < 4) /* XXX too short ? */ + continue; + /* This frame is up to offset i (not inclusive). + * We do not split it yet even if larger than MTU. + */ + f = create_video_frame(d + start, d+i, AST_FORMAT_H261, + pheader_len, cur); + + if (!f) + break; + /* recompute header with I=0, V=1 */ + h[0] = ( (sbit & 7) << 5 ) | ( (ebit & 7) << 2 ) | 1; + bcopy(h, f->data, 4); /* copy the h261 header */ + if (ebit) /* not aligned, restart from previous byte */ + i--; + sbit = (8 - ebit) & 7; + ebit = 0; + if (!cur) + first = f; + cur = f; + } + if (cur) + cur->subclass |= 1; // RTP Marker + + *tail = cur; + return first; +} + +/* + * Pieces might be unaligned so we really need to put them together. + */ +static int h261_decap(struct fbuf_t *b, uint8_t *data, int len) +{ + int ebit, sbit; + + if (len < 8) { + ast_log(LOG_WARNING, "invalid framesize %d\n", len); + return 1; + } + sbit = (data[0] >> 5) & 7; + ebit = (data[0] >> 2) & 7; + len -= 4; + data += 4; + return fbuf_append(b, data, len, sbit, ebit); +} + +static struct video_codec_desc h261_codec = { + .name = "h261", + .format = AST_FORMAT_H261, + .enc_init = h261_enc_init, + .enc_encap = h261_encap, + .enc_run = ffmpeg_encode, + .dec_init = NULL, + .dec_decap = h261_decap, + .dec_run = ffmpeg_decode +}; + +/* mpeg4 support */ +static int mpeg4_enc_init(AVCodecContext *enc_ctx) +{ +#if 0 + //enc_ctx->flags |= CODEC_FLAG_LOW_DELAY; /*don't use b frames ?*/ + enc_ctx->flags |= CODEC_FLAG_AC_PRED; + enc_ctx->flags |= CODEC_FLAG_H263P_UMV; + enc_ctx->flags |= CODEC_FLAG_QPEL; + enc_ctx->flags |= CODEC_FLAG_4MV; + enc_ctx->flags |= CODEC_FLAG_GMC; + enc_ctx->flags |= CODEC_FLAG_LOOP_FILTER; + enc_ctx->flags |= CODEC_FLAG_H263P_SLICE_STRUCT; +#endif + enc_ctx->rtp_payload_size = 0; /* important - ffmpeg fails otherwise */ + return 0; +} + +/* simplistic encapsulation - just split frames in mtu-size units */ +static struct ast_frame *mpeg4_encap(struct video_out_desc *out, + struct ast_frame **tail) +{ + struct ast_frame *f, *cur = NULL, *first = NULL; + uint8_t *d = out->enc_out.data; + uint8_t *end = d+out->enc_out.used; + int len; + + for (;d < end; d += len, cur = f) { + len = MIN(out->mtu, end-d); + f = create_video_frame(d, d+len, AST_FORMAT_MP4_VIDEO, 0, cur); + if (!f) + break; + if (!first) + first = f; + } + if (cur) + cur->subclass |= 1; + *tail = cur; + return first; +} + +static int mpeg4_decap(struct fbuf_t *b, uint8_t *data, int len) +{ + return fbuf_append(b, data, len, 0, 0); +} + +static int mpeg4_decode(struct video_in_desc *v, struct fbuf_t *b) +{ + int full_frame = 0, datalen = b->used; + int ret = avcodec_decode_video(v->dec_ctx, v->d_frame, &full_frame, + b->data, datalen); + if (ret < 0) { + ast_log(LOG_NOTICE, "Error decoding\n"); + ret = datalen; /* assume we used everything. */ + } + datalen -= ret; + if (datalen > 0) /* update b with leftover bytes */ + bcopy(b->data + ret, b->data, datalen); + b->used = datalen; + b->ebit = 0; + return full_frame; +} + +static struct video_codec_desc mpeg4_codec = { + .name = "mpeg4", + .format = AST_FORMAT_MP4_VIDEO, + .enc_init = mpeg4_enc_init, + .enc_encap = mpeg4_encap, + .enc_run = ffmpeg_encode, + .dec_init = NULL, + .dec_decap = mpeg4_decap, + .dec_run = mpeg4_decode +}; + +static int h264_enc_init(AVCodecContext *enc_ctx) +{ + enc_ctx->flags |= CODEC_FLAG_TRUNCATED; + //enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + //enc_ctx->flags2 |= CODEC_FLAG2_FASTPSKIP; + /* TODO: Maybe we need to add some other flags */ + enc_ctx->rtp_mode = 0; + enc_ctx->rtp_payload_size = 0; + enc_ctx->bit_rate_tolerance = enc_ctx->bit_rate; + return 0; +} + +static int h264_dec_init(AVCodecContext *dec_ctx) +{ + dec_ctx->flags |= CODEC_FLAG_TRUNCATED; + + return 0; +} + +/* + * The structure of a generic H.264 stream is: + * - 0..n 0-byte(s), unused, optional. one zero-byte is always present + * in the first NAL before the start code prefix. + * - start code prefix (3 bytes): 0x000001 + * (the first bytestream has a + * like these 0x00000001!) + * - NAL header byte ( F[1] | NRI[2] | Type[5] ) where type != 0 + * - byte-stream + * - 0..n 0-byte(s) (padding, unused). + * Segmentation in RTP only needs to be done on start code prefixes. + * If fragments are too long... we don't support it yet. + * - encapsulate (or fragment) the byte-stream (with NAL header included) + */ +static struct ast_frame *h264_encap(struct video_out_desc *out, + struct ast_frame **tail) +{ + struct ast_frame *f = NULL, *cur = NULL, *first = NULL; + uint8_t *d, *start = out->enc_out.data; + uint8_t *end = start + out->enc_out.used; + + /* Search the first start code prefix - ITU-T H.264 sec. B.2, + * and move start right after that, on the NAL header byte. + */ +#define HAVE_NAL(x) (x[-4] == 0 && x[-3] == 0 && x[-2] == 0 && x[-1] == 1) + for (start += 4; start < end; start++) { + int ty = start[0] & 0x1f; + if (HAVE_NAL(start) && ty != 0 && ty != 31) + break; + } + /* if not found, or too short, we just skip the next loop and are done. */ + + /* Here follows the main loop to create frames. Search subsequent start + * codes, and then possibly fragment the unit into smaller fragments. + */ + for (;start < end - 4; start = d) { + int size; /* size of current block */ + uint8_t hdr[2]; /* add-on header when fragmenting */ + int ty = 0; + + /* now search next nal */ + for (d = start + 4; d < end; d++) { + ty = d[0] & 0x1f; + if (HAVE_NAL(d)) + break; /* found NAL */ + } + /* have a block to send. d past the start code unless we overflow */ + if (d >= end) { /* NAL not found */ + d = end + 4; + } else if (ty == 0 || ty == 31) { /* found but invalid type, skip */ + ast_log(LOG_WARNING, "skip invalid nal type %d at %d of %d\n", + ty, d - out->enc_out.data, out->enc_out.used); + continue; + } + + size = d - start - 4; /* don't count the end */ + + if (size < out->mtu) { // test - don't fragment + // Single NAL Unit + f = create_video_frame(start, d - 4, AST_FORMAT_H264, 0, cur); + if (!f) + break; + if (!first) + first = f; + + cur = f; + continue; + } + + // Fragmented Unit (Mode A: no DON, very weak) + hdr[0] = (*start & 0xe0) | 28; /* mark as a fragmentation unit */ + hdr[1] = (*start++ & 0x1f) | 0x80 ; /* keep type and set START bit */ + size--; /* skip the NAL header */ + while (size) { + uint8_t *data; + int frag_size = MIN(size, out->mtu); + + f = create_video_frame(start, start+frag_size, AST_FORMAT_H264, 2, cur); + if (!f) + break; + size -= frag_size; /* skip this data block */ + start += frag_size; + + data = f->data; + data[0] = hdr[0]; + data[1] = hdr[1] | (size == 0 ? 0x40 : 0); /* end bit if we are done */ + hdr[1] &= ~0x80; /* clear start bit for subsequent frames */ + if (!first) + first = f; + cur = f; + } + } + + if (cur) + cur->subclass |= 1; // RTP Marker + + *tail = cur; + + return first; +} + +static int h264_decap(struct fbuf_t *b, uint8_t *data, int len) +{ + /* Start Code Prefix (Annex B in specification) */ + uint8_t scp[] = { 0x00, 0x00, 0x00, 0x01 }; + int retval = 0; + int type, ofs = 0; + + if (len < 2) { + ast_log(LOG_WARNING, "--- invalid len %d\n", len); + return 1; + } + /* first of all, check if the packet has F == 0 */ + if (data[0] & 0x80) { + ast_log(LOG_WARNING, "--- forbidden packet; nal: %02x\n", + data[0]); + return 1; + } + + type = data[0] & 0x1f; + switch (type) { + case 0: + case 31: + ast_log(LOG_WARNING, "--- invalid type: %d\n", type); + return 1; + case 24: + case 25: + case 26: + case 27: + case 29: + ast_log(LOG_WARNING, "--- encapsulation not supported : %d\n", type); + return 1; + case 28: /* FU-A Unit */ + if (data[1] & 0x80) { // S == 1, import F and NRI from next + data[1] &= 0x1f; /* preserve type */ + data[1] |= (data[0] & 0xe0); /* import F & NRI */ + retval = fbuf_append(b, scp, sizeof(scp), 0, 0); + ofs = 1; + } else { + ofs = 2; + } + break; + default: /* From 1 to 23 (Single NAL Unit) */ + retval = fbuf_append(b, scp, sizeof(scp), 0, 0); + } + if (!retval) + retval = fbuf_append(b, data + ofs, len - ofs, 0, 0); + if (retval) + ast_log(LOG_WARNING, "result %d\n", retval); + return retval; +} + +static struct video_codec_desc h264_codec = { + .name = "h264", + .format = AST_FORMAT_H264, + .enc_init = h264_enc_init, + .enc_encap = h264_encap, + .enc_run = ffmpeg_encode, + .dec_init = h264_dec_init, + .dec_decap = h264_decap, + .dec_run = ffmpeg_decode +}; + +/* + * Table of translation between asterisk and ffmpeg formats. + * We need also a field for read and write (encoding and decoding), because + * e.g. H263+ uses different codec IDs in ffmpeg when encoding or decoding. + */ +struct _cm { /* map ffmpeg codec types to asterisk formats */ + uint32_t ast_format; /* 0 is a terminator */ + enum CodecID codec; + enum { CM_RD = 1, CM_WR = 2, CM_RDWR = 3 } rw; /* read or write or both ? */ + struct video_codec_desc *codec_desc; +}; + +static struct _cm video_formats[] = { + { AST_FORMAT_H263_PLUS, CODEC_ID_H263, CM_RD }, /* incoming H263P ? */ + { AST_FORMAT_H263_PLUS, CODEC_ID_H263P, CM_WR }, + { AST_FORMAT_H263, CODEC_ID_H263, CM_RD }, + { AST_FORMAT_H263, CODEC_ID_H263, CM_WR }, + { AST_FORMAT_H261, CODEC_ID_H261, CM_RDWR }, + { AST_FORMAT_H264, CODEC_ID_H264, CM_RDWR }, + { AST_FORMAT_MP4_VIDEO, CODEC_ID_MPEG4, CM_RDWR }, + { 0, 0, 0 }, +}; + + +/*! \brief map an asterisk format into an ffmpeg one */ +static enum CodecID map_video_format(uint32_t ast_format, int rw) +{ + struct _cm *i; + + for (i = video_formats; i->ast_format != 0; i++) + if (ast_format & i->ast_format && rw & i->rw && rw & i->rw) + return i->codec; + return CODEC_ID_NONE; +} + +/* pointers to supported codecs. We assume the first one to be non null. */ +static struct video_codec_desc *supported_codecs[] = { + &h263p_codec, + &h264_codec, + &h263_codec, + &h261_codec, + &mpeg4_codec, + NULL +}; + +/* + * Map the AST_FORMAT to the library. If not recognised, fail. + * This is useful in the input path where we get frames. + */ +static struct video_codec_desc *map_video_codec(int fmt) +{ + int i; + + for (i = 0; supported_codecs[i]; i++) + if (fmt == supported_codecs[i]->format) { + ast_log(LOG_WARNING, "using %s for format 0x%x\n", + supported_codecs[i]->name, fmt); + return supported_codecs[i]; + } + return NULL; +} + +/*------ end codec specific code -----*/ |