root/vic/branches/mpeg4/codec/encoder-h264.cpp @ 4476

Revision 4476, 5.8 KB (checked in by douglask, 5 years ago)

Ensure that the H264 and MPEG4 encoders let VIC know that their frame format is YUV 420 (not CIF).

Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <math.h>
5#include <errno.h>
6#include <assert.h>
7#include <iostream>
8
9#include "inet.h"
10#include "net.h"
11#include "rtp.h"
12#include "vic_tcl.h"
13#include "transmitter.h"
14#include "pktbuf-rtp.h"
15#include "module.h"
16
17#include "databuffer.h"
18#include "x264encoder.h"
19#include "deinterlace.h"
20/*extern "C"
21{
22#include "base64.h"
23}*/
24
25static Transmitter *tx;
26static RTP_BufferPool *pool;
27static u_int32_t ts;
28static unsigned char frame_seq;
29
30class H264Encoder:public TransmitterModule
31{
32  public:
33    H264Encoder();
34    ~H264Encoder();
35
36    void setq(int q);
37    int command(int argc, const char *const *argv);
38
39    void size(int w, int h);
40    int consume(const VideoFrame *);
41
42  protected:
43    int fps, kbps, gop;
44    bool state;
45    //UCHAR* bitstream;
46
47    x264Encoder *enc;
48    DataBuffer *fOut;
49    Deinterlace deinterlacer;
50
51    FILE *fptr;
52};
53
54static class H264EncoderMatcher:public Matcher
55{
56  public:
57    H264EncoderMatcher():Matcher("module")
58    {
59    }
60    TclObject *match(const char *fmt)
61    {
62        if (strcasecmp(fmt, "h264") == 0)
63            return (new H264Encoder);
64        return (0);
65    }
66}
67
68encoder_matcher_h264;
69
70H264Encoder::H264Encoder():TransmitterModule(FT_YUV_CIF)
71{
72    enc = new x264Encoder();
73    state = false;
74    fptr = NULL;
75    frame_seq = 0;
76    fps = 20;
77    kbps = 512;
78    gop = 20;
79    fOut=NULL;
80}
81
82H264Encoder::~H264Encoder()
83{
84    delete enc;
85    if (fOut) delete fOut;
86}
87
88void H264Encoder::size(int w, int h)
89{
90    debug_msg("H264: WxH %dx%d\n", w, h);
91    Module::size(w, h);
92    fOut = new DataBuffer(w * h * 3 >> 2);
93}
94
95int H264Encoder::command(int argc, const char *const *argv)
96{
97    if (argc == 2) {
98        if (strcmp(argv[1], "frame-format") == 0) {
99            Tcl& tcl = Tcl::instance();
100            tcl.result("420");
101            return (TCL_OK);
102        }
103    }
104    else if (argc == 3) {
105        if (strcmp(argv[1], "q") == 0) {
106            gop = atoi(argv[2]);
107            return (TCL_OK);
108        }
109        else if (strcmp(argv[1], "fps") == 0) {
110            fps = atoi(argv[2]);
111            //std::cout << "H264: fps " << fps << "\n";
112            return (TCL_OK);
113        }
114        else if (strcmp(argv[1], "kbps") == 0) {
115            kbps = atoi(argv[2]);
116            if (kbps < 64)
117                kbps = 64;
118            //std::cout << "H264: kbps " << kbps << "\n";
119            return (TCL_OK);
120        }
121        else if (strcmp(argv[1], "hq") == 0) {
122            int enable_hq = atoi(argv[2]);
123            return (TCL_OK);
124        }
125    }
126    return (TransmitterModule::command(argc, argv));
127    return 0;
128}
129
130int H264Encoder::consume(const VideoFrame * vf)
131{
132    pktbuf *pb;
133    rtphdr *rh;
134    ts = vf->ts_;
135    tx = tx_;
136    pool = pool_;
137
138    int numNAL, i, sent_size = 0;
139    int frame_size = 0;
140    unsigned char f_seq = 0;
141    //unsigned char f_total_pkt = 0;
142    int RTP_HDR_LEN = sizeof(rtphdr);
143    int NAL_FRAG_THRESH = tx->mtu() - RTP_HDR_LEN; /* payload max in one packet */
144    //debug_msg( "MTU=%d, RTP_HDR_LEN=%d\n", NAL_FRAG_THRESH, RTP_HDR_LEN);
145
146
147    tx->flush();
148
149    if (!state) {
150            state = true;
151            size(vf->width_, vf->height_);
152            debug_msg("init x264 encoder with kbps:%d, fps:%d", kbps, fps);
153            enc->init(vf->width_, vf->height_, kbps, fps);
154            enc->setGOP(gop);
155            frame_size = vf->width_ * vf->height_;
156    }
157
158    frame_size = vf->width_ * vf->height_;
159    deinterlacer.render(vf->bp_, vf->width_, vf->height_);
160    enc->encodeFrame(vf->bp_);
161    numNAL = enc->numNAL();
162
163    //Send out numNAL packets framed according to RFC3984
164    for (i = 0; i < numNAL; i++) {
165
166        bool firstFragment = true;
167        int FU_HDR_LEN = 1;
168        int offset = 0;
169
170        enc->getNALPacket(i, fOut);
171        int nalSize1 = fOut->getDataSize();
172        int nalSize = nalSize1-5;
173        char *data1 = fOut->getData();
174        char *data = fOut->getData();
175        uint8_t NALhdr = data1[4]; //SV-XXX why does our x.264 provide 4-byte StartSync in the NALU?
176        uint8_t NALtype = NALhdr & 0x1f;
177        //debug_msg( "Got NALhdr=0x%02x, NALtype=0x%02x from encoded frame.\n", NALhdr, NALtype);
178        memcpy(data, &data1[5], nalSize);
179
180        sent_size += nalSize;
181
182
183        while (nalSize > 0) {
184            pb = pool->alloc(vf->ts_, RTP_PT_H264);
185            rh = (rtphdr *) pb->data;
186
187            if (nalSize <= NAL_FRAG_THRESH) {
188                //==============================================
189                //Single NAL or last fragment of FU-A
190                //==============================================
191
192                rh->rh_flags |= htons(RTP_M);   // set M bit
193                pb->len = nalSize + RTP_HDR_LEN + FU_HDR_LEN;
194
195                debug_msg( "NAL : ");
196
197                if (FU_HDR_LEN==2) {
198                        //==============================================
199                        //Last fragment of FU-A
200                        //==============================================
201                        pb->data[12] = 0x00 | (NALhdr & 0x60) | 28;     //FU indicator
202                        pb->data[13] = 0x40  | NALtype;                 //FU header
203                       
204                        debug_msg( "FU_Indicator=0x%02x, FU_Header=0x%02x, ", pb->data[12], pb->data[13]);
205                }
206                else {
207                        pb->data[12] = NALhdr;                          //NAL Header
208                        debug_msg( "-----------------, --------------, ");
209                }
210
211                memcpy(&pb->data[RTP_HDR_LEN + FU_HDR_LEN], data + offset, nalSize);
212
213                debug_msg( "i=%d/%d, nalSize=%4d len=%4d firstFrag=%d offset=%4d\n", i, numNAL, nalSize, pb->len, firstFragment, offset);
214
215                nalSize = 0;
216                offset = 0;
217
218            } else {
219                //==============================================
220                //FU-A (not the last fragment though)
221                //==============================================
222
223                FU_HDR_LEN = 2;
224                pb->len = (NAL_FRAG_THRESH - FU_HDR_LEN) + RTP_HDR_LEN + FU_HDR_LEN;
225
226                pb->data[12] = 0x00 | (NALhdr & 0x60) | 28;                     //FU indicator
227                pb->data[13] = ( (firstFragment) ? 0x80 : 0x00 ) | NALtype;     //FU header
228
229                memcpy(&pb->data[RTP_HDR_LEN + FU_HDR_LEN], data + offset, NAL_FRAG_THRESH - FU_HDR_LEN);
230
231                //debug_msg( "FU-A: FU_Indicator=0x%02x, FU_Header=0x%02x, i=%d/%d, nalSize=%4d len=%4d firstFrag=%d offset=%4d\n",  pb->data[12], pb->data[13], i, numNAL, nalSize, pb->len, firstFragment, offset);
232
233                nalSize -= (NAL_FRAG_THRESH-FU_HDR_LEN);
234                offset += (NAL_FRAG_THRESH-FU_HDR_LEN);
235                firstFragment = false;
236            }
237
238            tx->send(pb);
239            f_seq++;
240        }
241
242    }
243
244    frame_seq++;
245
246
247    return (kbps*1024) / (fps*8);
248}
Note: See TracBrowser for help on using the browser.