使用三方摄像头,实现pjsip的视频通话功能

提要:

近期一直在做视频通话功能,主要基于pjsip来实现的,将这些过程记录下来,可能对做同类型工作的同学有所帮助!


实现思路,参考pjsip原来设备采集视频、编码并rtp组包发送的思路,再在原有流程中做修改!

主要关键点:

1、摄像头采集完成后已经是已编码的H264/H265的流,不需要再开启pjsip的编码/解码流程;

2、组包发送,H264的FU-A组包、PS封装发送;


首先梳理流程,具体包括下面几个点:

1. 摄像头设备适配(这里可以考虑多个数据源,包括文件、socket或者摄像头的数据源;)

2. 参考android_dev.c 实现一个ov5000_dev.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/* $Id$ */
/*
 * Copyright (C) 2015 Teluu Inc. (http://www.teluu.com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#include "util.h"
#include <pjmedia-videodev/videodev_imp.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/math.h>
#include <pj/os.h>
 
//#define ARM_LINUX
#define VIDEO_USE_SOCKET
  
 
 
extern void set_take_ps_packet(int enable_value);
int log_printf(int a,...)
{
    return 0;
}
#define PJMEDIA_VIDEO_DEV_HAS_OV5000 1
#if defined(PJMEDIA_HAS_VIDEO) && PJMEDIA_HAS_VIDEO != 0 && \
    defined(PJMEDIA_VIDEO_DEV_HAS_OV5000) 
  
 
#define THIS_FILE      "ov5000_dev.c"
 
/* Default video params */
#define DEFAULT_CLOCK_RATE 90000
#define DEFAULT_WIDTH      352
#define DEFAULT_HEIGHT     288
#define DEFAULT_FPS        15
#define ALIGN16(x)     ((((x)+15) >> 4) << 4)
 
/* Define whether we should maintain the aspect ratio when rotating the image.
 * For more details, please refer to util.h.
 */
#define MAINTAIN_ASPECT_RATIO     PJ_TRUE
 
#define JNIEnv (void *)
/* Format map info */
typedef struct ov5000_fmt_map
{
    pjmedia_format_id   fmt_id;
    pj_uint32_t     ov5000_fmt_id;
} ov5000_fmt_map;
 
 
/* Format map.
 * Note: it seems that most of Ov5000 devices don't support I420, while
 * unfortunately, our converter (libyuv based) only support I420 & RGBA,
 * so in this case, we'd just pretend that we support I420 and we'll do
 * the NV21/YV12 -> I420 conversion here.
 */
static ov5000_fmt_map fmt_map[] =
{
    {PJMEDIA_FORMAT_NV21, 0x00000011},
    {PJMEDIA_FORMAT_YV12, 0x32315659},
    {PJMEDIA_FORMAT_I420, 0x00000023}, /* YUV_420_888 */
};
 
 
/* Device info */
typedef struct ov5000_dev_info
{
    pjmedia_vid_dev_info     info;     /**< Base info         */
    unsigned             dev_idx;  /**< Original dev ID   */
    pj_bool_t            facing;   /**< Front/back camera?*/
    unsigned             sup_size_cnt; /**< # of supp'd size  */
    pjmedia_rect_size       *sup_size;  /**< Supported size    */
    unsigned             sup_fps_cnt;  /**< # of supp'd FPS   */
    pjmedia_rect_size       *sup_fps;   /**< Supported FPS     */
    pj_bool_t            has_yv12; /**< Support YV12?     */
    pj_bool_t            has_nv21; /**< Support NV21?     */
    pj_bool_t            forced_i420;  /**< Support I420 with
                             conversion        */
} ov5000_dev_info;
 
 
/* Video factory */
typedef struct ov5000_factory
{
    pjmedia_vid_dev_factory  base;     /**< Base factory      */
    pj_pool_t           *pool;      /**< Memory pool       */
    pj_pool_factory     *pf;        /**< Pool factory      */
 
    pj_pool_t           *dev_pool;  /**< Device list pool  */
    unsigned             dev_count;    /**< Device count      */
    ov5000_dev_info     *dev_info;  /**< Device info list  */
} ov5000_factory;
 
 
/* Video stream. */
typedef struct ov5000_stream
{
    pjmedia_vid_dev_stream  base;     /**< Base stream       */
    pjmedia_vid_dev_param   param;       /**< Settings          */
    pj_pool_t          *pool;        /**< Memory pool       */
    ov5000_factory         *factory;            /**< Factory           */
     
    pjmedia_vid_dev_cb      vid_cb;     /**< Stream callback   */
    void           *user_data;          /**< Application data  */
    pj_bool_t           is_running;     /**< Stream running?   */
     
    void*           jcam;       /**< PjCamera instance */
 
    pj_timestamp            frame_ts;       /**< Current timestamp */
    unsigned                ts_inc;     /**< Timestamp interval*/
    unsigned            convert_to_i420;    /**< Need to convert to I420?
                             0: no
                             1: from NV21
                             2: from YV12    */
     
    /** Capture thread info */
    pj_bool_t           thread_initialized;
    pj_thread_desc      thread_desc;
    pj_thread_t        *thread;
 
    /** NV21/YV12 -> I420 Conversion buffer  */
    pj_uint8_t         *convert_buf;
    pjmedia_rect_size       cam_size;
     
    /** Converter to rotate frame  */
    pjmedia_vid_dev_conv    conv;
 
    //
    pj_uint8_t *sps_pps;
    int sps_pps_p_index;
    int pps_len;
    int sps_pps_len;
    int recive_video_packet_count;
     
     
    /** Frame format param for NV21/YV12 -> I420 conversion */
    pjmedia_video_apply_fmt_param vafp;
 
    //capture thread.
    pj_thread_t     *ca_thread;
} ov5000_stream;
 
 
/* Prototypes */
static pj_status_t ov5000_factory_init(pjmedia_vid_dev_factory *f);
static pj_status_t ov5000_factory_destroy(pjmedia_vid_dev_factory *f);
static pj_status_t ov5000_factory_refresh(pjmedia_vid_dev_factory *f); 
static unsigned    ov5000_factory_get_dev_count(pjmedia_vid_dev_factory *f);
static pj_status_t ov5000_factory_get_dev_info(pjmedia_vid_dev_factory *f,
                        unsigned index,
                        pjmedia_vid_dev_info *info);
static pj_status_t ov5000_factory_default_param(pj_pool_t *pool,
                                             pjmedia_vid_dev_factory *f,
                         unsigned index,
                         pjmedia_vid_dev_param *param);
static pj_status_t ov5000_factory_create_stream(
                    pjmedia_vid_dev_factory *f,
                    pjmedia_vid_dev_param *param,
                    const pjmedia_vid_dev_cb *cb,
                    void *user_data,
                    pjmedia_vid_dev_stream **p_vid_strm);
 
 
static pj_status_t ov5000_stream_get_param(pjmedia_vid_dev_stream *strm,
                                        pjmedia_vid_dev_param *param);
static pj_status_t ov5000_stream_get_cap(pjmedia_vid_dev_stream *strm,
                                      pjmedia_vid_dev_cap cap,
                                      void *value);
static pj_status_t ov5000_stream_set_cap(pjmedia_vid_dev_stream *strm,
                                      pjmedia_vid_dev_cap cap,
                                      const void *value);
static pj_status_t ov5000_stream_start(pjmedia_vid_dev_stream *strm);
static pj_status_t ov5000_stream_stop(pjmedia_vid_dev_stream *strm);
static pj_status_t ov5000_stream_destroy(pjmedia_vid_dev_stream *strm);
static void  OnGetFrame2(uint8_t* data, int length, void* user_data);
 
 
/* Operations */
static pjmedia_vid_dev_factory_op factory_op =
{
    &ov5000_factory_init,
    &ov5000_factory_destroy,
    &ov5000_factory_get_dev_count,
    &ov5000_factory_get_dev_info,
    &ov5000_factory_default_param,
    &ov5000_factory_create_stream,
    &ov5000_factory_refresh
};
 
static pjmedia_vid_dev_stream_op stream_op =
{
    &ov5000_stream_get_param,
    &ov5000_stream_get_cap,
    &ov5000_stream_set_cap,
    &ov5000_stream_start,
    NULL,
    NULL,
    &ov5000_stream_stop,
    &ov5000_stream_destroy
};
 
  
#endif  /* PJMEDIA_VIDEO_DEV_HAS_Ov5000 */


3. ov5000_dev摄像头采集的数据最终会回调到strm->vid_cb.capture_cb ,这个回调方法是video_port.c中的vidstream_cap_cb方法;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static void copy_frame_to_buffer(pjmedia_vid_port *vp,
                                 pjmedia_frame *frame)
{
    if (frame == NULL){
        return;
    }
    pj_mutex_lock(vp->frm_mutex);
    #if PJMEDIA_VIDEO_DEV_HAS_OV5000
     //PJ_LOG(4, (THIS_FILE, "-1--copy_frame_to_buffer: frame.size:%d, %d len", frame->size, vp->frm_buf->size));
        #if 1
        if (vp->frm_buf == NULL){
            pj_mutex_unlock(vp->frm_mutex);
            return;
        }
 
        ringput(frame->buf, frame->size, 0);
        vp->frm_buf->size = frame->size;
            vp->frm_buf->type = frame->type;
            vp->frm_buf->timestamp = frame->timestamp;
            vp->frm_buf->bit_info = frame->bit_info;
        #else
        //direct put frame?
            pjmedia_frame_copy(vp->frm_buf, frame);
         
        #endif
    #endif//
    pj_mutex_unlock(vp->frm_mutex);
}


另外,vid_port中的frm_buf缓存数据太少,数据帧存在明显的跳帧现象,所以参考之前的fifobuffer思路,实现了一个fifobuffer;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
//add for ring buffer
#if PJMEDIA_VIDEO_DEV_HAS_OV5000
pthread_mutex_t ring_mutex;
 
struct ringbuf {
    unsigned char *buffer;
    int frame_type;
    int size;
};
static int addring (int i);
static int ringget(struct ringbuf *getinfo);
static void ringput(unsigned char *buffer,int size,int encode_type);
static void ringfree();
static void ringmalloc(int size);
static void ringreset();
 
 
#define NMAX 10//30
#define RING_BUFFER_SIZE 145000//50000
  
static volatile  int iput = 0; /*   */
static volatile  int iget = 0; /* */
static volatile  int n = 0; /* */
#define USE_MALLOC_MEM
#ifndef USE_MALLOC_MEM
static uint8_t mem_buffer[RING_BUFFER_SIZE*NMAX];
#endif
static volatile struct ringbuf ringfifo[NMAX]; 
static volatile int init_flag = 0;
 
static void ringmalloc(int size)
{
    int i;
    #ifdef USE_MALLOC_MEM
    //
    pthread_mutex_init(&ring_mutex, 0);
    if (init_flag){ 
        return;
    }
    for(i =0; i<NMAX; i++)
    {  
        ringfifo[i].buffer = malloc(size);
        ringfifo[i].size = 0;
        ringfifo[i].frame_type = 0;
       // printf("FIFO INFO:idx:%d,len:%d,ptr:%x\n",i,ringfifo[i].size,(int)(ringfifo[i].buffer));
    }
    init_flag = 1;
    #else
    for(i =0; i<NMAX; i++)
    
        ringfifo[i].buffer = &mem_buffer[i*RING_BUFFER_SIZE];
        ringfifo[i].size = 0;
        ringfifo[i].frame_type = 0;
       // printf("FIFO INFO:idx:%d,len:%d,ptr:%x\n",i,ringfifo[i].size,(int)(ringfifo[i].buffer));
    }
    #endif
    iput = 0; /* ?隆陇D??o3???娄脤?娄脤隆脌?隆茫隆陇?篓篓????? */
    iget = 0; /* ?o3???娄脤?娄脤隆脌?隆茫篓篓?3????? */
    n = 0; /* ?隆陇D??o3????D娄脤??a??隆脕篓鹿篓潞y篓垄? */
}
/**************************************************************************************************
**
**
**
**************************************************************************************************/
static void ringreset()
{
 
    pthread_mutex_lock(&ring_mutex);
    iput = 0; /* ?隆陇D??o3???娄脤?娄脤隆脌?隆茫隆陇?篓篓????? */
    iget = 0; /* ?o3???娄脤?娄脤隆脌?隆茫篓篓?3????? */
    n = 0; /* ?隆陇D??o3????D娄脤??a??隆脕篓鹿篓潞y篓垄? */ 
    pthread_mutex_unlock(&ring_mutex);
}
/**************************************************************************************************
**
**
**
**************************************************************************************************/
static void ringfree(void)
{
    int i;
    printf("begin free mem\n");
    for(i =0; i<NMAX; i++)
    {
       // printf("FREE FIFO INFO:idx:%d,len:%d,ptr:%x\n",i,ringfifo[i].size,(int)(ringfifo[i].buffer));
    #ifdef USE_MALLOC_MEM
       free(ringfifo[i].buffer);
     ringfifo[i].buffer = NULL;
    #endif//#ifdef USE_MALLOC_MEM
        ringfifo[i].size = 0;
    }
    init_flag = 0;
    //pthread_mutex_destroy(&ring_mutex);
}
/**************************************************************************************************
**
**
**
**************************************************************************************************/
static int addring(int i)
{
    return (i+1) == NMAX ? 0 : i+1;
}
 
/**************************************************************************************************
**
**
**
**************************************************************************************************/ 
 
static int ringget(struct ringbuf *getinfo)
{
    int Pos;
    if(n>0)
    {
        pthread_mutex_lock(&ring_mutex);
        Pos = iget;
        iget = addring(iget);
        n--;
        getinfo->buffer = (ringfifo[Pos].buffer);
        if (getinfo->buffer == NULL){
            pthread_mutex_unlock(&ring_mutex);
            return 0;
        }
        getinfo->frame_type = ringfifo[Pos].frame_type;
        getinfo->size = ringfifo[Pos].size;
        pthread_mutex_unlock(&ring_mutex);
        //printf("Get FIFO INFO:idx:%d,len:%d,ptr:%x,type:%d\n",Pos,getinfo->size,(int)(getinfo->buffer),getinfo->frame_type);
        return ringfifo[Pos].size;
    }
    else
    {
        //printf("Buffer is empty\n");
        return 0;
    }
}
/**************************************************************************************************
**
**
**
**************************************************************************************************/ 
static void ringput(unsigned char *buffer,int size,int encode_type)
{
 
    if (size > RING_BUFFER_SIZE){
        PJ_PERROR(4,(THIS_FILE, 0, "Error ringput, size:%d > %d", size, RING_BUFFER_SIZE));
        return;
    }
    if(n >= 0 && n<NMAX)
    {
        pthread_mutex_lock(&ring_mutex);
        if (ringfifo[iput].buffer == NULL){
            pthread_mutex_unlock(&ring_mutex);
            return;
        }
        if (size > RING_BUFFER_SIZE){
                //pthread_mutex_unlock(&ring_mutex);
            //return;
            ringfifo[iput].buffer = realloc(ringfifo[iput].buffer, size);
        
        memcpy(ringfifo[iput].buffer,buffer,size);
        ringfifo[iput].size= size;
        ringfifo[iput].frame_type = encode_type;
        //printf("Put FIFO INFO:idx:%d,len:%d,ptr:%x,type:%d\n",iput,ringfifo[iput].size,(int)(ringfifo[iput].buffer),ringfifo[iput].frame_type);
        iput = addring(iput);
        pthread_mutex_unlock(&ring_mutex);
        n++;
    }
    else
    {
        //  printf("Buffer is full\n");
    }
}
  
#endif
//add end.
 
 
vid_port.c中的get_frame_from_buffer做如下修改:
static pj_status_t get_frame_from_buffer(pjmedia_vid_port *vp,
                                         pjmedia_frame *frame)
{
    pj_status_t status = PJ_SUCCESS;
 
    pj_mutex_lock(vp->frm_mutex);
    if (vp->conv.conv)
        status = convert_frame(vp, vp->frm_buf, frame);
    else{
         
        //for bug
        //PJ_LOG(4, (THIS_FILE, "-1--get_frame_from_buffer: frame.size:%d, %d len", frame->size, vp->frm_buf->size));
      
        #if PJMEDIA_VIDEO_DEV_HAS_OV5000
        struct ringbuf ringitem ;
        int itemlen  = ringget(&ringitem);
        if (itemlen > 0 && frame->buf != NULL){
            int copy_len = itemlen;
            if (itemlen > frame->size){
                copy_len = frame->size;   
            }
            memcpy(frame->buf, ringitem.buffer, copy_len);
            frame->size = copy_len;
        }else{
            frame->size = 0;
                pj_mutex_unlock(vp->frm_mutex);
            return -1;
        }
        if (vp->frm_buf != NULL){
           frame->type = vp->frm_buf->type;
           frame->timestamp = vp->frm_buf->timestamp;
           frame->bit_info = vp->frm_buf->bit_info;
           //PJ_LOG(4, (THIS_FILE, "-2--get_frame_from_buffer: frame.size:%d, %d len, itemlen:%d", frame->size, vp->frm_buf->size, itemlen));
     
        }
        #else
        int itemlen  = vp->frm_buf->size;
        pjmedia_frame_copy(frame, vp->frm_buf);
        #endif
        }
    pj_mutex_unlock(vp->frm_mutex);
     
    return status;
}



3. 视频帧获取驱动定时器适配,调试发现视频流卡顿明显,发现是驱动的定时器跑的太慢,涉及到vid_conf.c中的on_clock_tick方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    clock_param.clock_rate = 900000;//TS_CLOCK_RATE;   
    clock_param.usec_interval = 1000000 /1000;// vid_conf->opt.frame_rate;
    status = pjmedia_clock_create2(pool, &clock_param, 0, &on_clock_tick,
                                   vid_conf, &vid_conf->clock);
                                    
                                    
    #if PJMEDIA_VIDEO_DEV_HAS_OV5000//lyz@ no need converter
 
    vp->conv.conv_param.src.id = vp->conv.conv_param.dst.id;
    vp->conv.conv_param.src.det.vid.size.w = vp->conv.conv_param.dst.det.vid.size.w;
    vp->conv.conv_param.src.det.vid.size.h= vp->conv.conv_param.dst.det.vid.size.h;
    //vp->role = ROLE_ACTIVE;
        //return PJ_SUCCESS;
    #endif
     
vconf_port结构体中增加
    pj_size_t        get_buf_real_size;    /**< Data size for get_frame().   */
    pj_size_t       put_buf_real_size;  /**< Data size for put_frame().   */
 
on_clock_tick方法中
                status = pjmedia_port_get_frame(src->port, &frame);
                if (status != PJ_SUCCESS) {
                    PJ_PERROR(5, (THIS_FILE, status,
                                  "Failed to get frame from port %d [%s]!",
                                  src->idx, src->port->info.name.ptr));
                    src->got_frame = PJ_FALSE;
                else {
            #if PJMEDIA_VIDEO_DEV_HAS_OV5000//just set got_frame by 
               //PJ_PERROR(4, (THIS_FILE, status, "get frame from port %d  ,len:%d, src_buf_size:%d!", src->idx, frame.size, src->get_buf_size));
            src->got_frame = PJ_TRUE;
            src->get_buf_real_size = frame.size;
            #else
                src->got_frame = (frame.size == src->get_buf_size);
            #endif
 
                    /* There is a possibility that the source port's format has
                     * changed, but we haven't received the event yet.
                     */
                    cur_fmt = &src->format;
                    new_fmt = &src->port->info.fmt;
                    if (cmp_fps(cur_fmt, new_fmt) ||
                        cmp_size(cur_fmt, new_fmt))
                    {
                        op_param prm;
                        prm.update_port.port = src->idx;
                        op_update_port(vid_conf, &prm);
                    }
                }
 
                render_src_frame方法中做下面的修改
static pj_status_t render_src_frame(vconf_port *src, vconf_port *sink,
                                    unsigned transmitter_idx)
    if (sink->transmitter_cnt == 1 && (!rs || !rs->converter)) {
        /* The only transmitter and no conversion needed */
        #if PJMEDIA_VIDEO_DEV_HAS_OV5000//just set got_frame  
        int get_buf_size = src->get_buf_real_size < sink->put_buf_size?src->get_buf_real_size:sink->put_buf_size;
        sink->put_buf_real_size = get_buf_size;
        #else
        /* The only transmitter and no conversion needed */
        if (src->get_buf_size != sink->put_buf_size)
            return PJMEDIA_EVID_BADFORMAT;
        int get_buf_size = src->put_buf_size;
        #endif//
        pj_memcpy(sink->put_buf, src->get_buf, get_buf_size);
    else if (rs && rs->converter) {


4、rtp h264 fu-a组包发送和回调,涉及的文件,vid_stream.c 的 put_frame 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
   /*
     mark need modify later.
   */
   #if PJMEDIA_VIDEO_DEV_HAS_OV5000
   int rtp_per_packet_len = 1200;//1300;
   int i=0;
   int send_len = 0;
   int reserved_len = frame->size;
   int data_start_index = 0;
 
#if 1//SUPPORT_PS_ENPACKED
    char ps_header[PS_HDR_LEN];
 
    char ps_system_header[SYS_HDR_LEN];
 
    char ps_map_header[PSM_HDR_LEN];
 
    char pes_header[PES_HDR_LEN];
    char temp_frame[1024 * 128];
#endif//
 
   uint8_t nalu = 0;
   uint8_t *data = (uint8_t *)frame->buf;
    if ( *data == 0x00 && *(data+1)==0x00 && *(data+2) == 0x00 && *(data+3) == 0x01){
        nalu = *(data+4);
        data_start_index = 4;
        if (reserved_len > rtp_per_packet_len){
            //fu-a
            data_start_index = 5;        
        }
    }else  if ( *data == 0x00 && *(data+1)==0x00 && *(data+2) == 0x01 ){
        nalu = *(data+3); 
        data_start_index = 3;
        if (reserved_len > rtp_per_packet_len){
            //fu-a
            data_start_index = 4;          
        }
    }else{
        nalu = *(data);
        data_start_index = 0;
    }
     
      int index = 0;
    if (ps_packet_flag){
         
        int time_base = 90000;
        int fps = 24;
        int send_packet_interval = 1000 / fps;
 
        int interval = time_base / fps;
        stream->pts += interval;
           long pts = stream->pts;
        //ps封装
        if (nalu == 0x67 || nalu == 0x68 || nalu == 0x65){
            //I frame
                gb28181_make_ps_header(ps_header, pts);
                memcpy(temp_frame,ps_header,PS_HDR_LEN);
                index += PS_HDR_LEN;
                gb28181_make_sys_header(ps_system_header, 0x3f);
 
                memcpy(temp_frame+ index, ps_system_header, SYS_HDR_LEN);
                index += SYS_HDR_LEN;
 
                gb28181_make_psm_header(ps_map_header);
 
                memcpy(temp_frame + index, ps_map_header, PSM_HDR_LEN);
                index += PSM_HDR_LEN;
             
        }else{
 
                gb28181_make_ps_header(ps_header, pts);
 
                memcpy(temp_frame, ps_header, PS_HDR_LEN);
                index += PS_HDR_LEN;
        }
            //封装pes
            gb28181_make_pes_header(pes_header, 0xe0, reserved_len, pts, pts);
 
            memcpy(temp_frame+index, pes_header, PES_HDR_LEN);
            index += PES_HDR_LEN;
 
            memcpy(temp_frame + index, data, reserved_len);
            index += reserved_len;
             
            data = temp_frame;
          reserved_len = index;
          data_start_index = 0; 
    }else{
        //data_start_index = 0;
        reserved_len -= data_start_index;
       }
    
    while(1){
         send_len = rtp_per_packet_len;
        if (reserved_len < rtp_per_packet_len){
            send_len = reserved_len;
            has_more_data = PJ_FALSE;
        }else{
            has_more_data = PJ_TRUE;
        }
         
        status = pjmedia_rtp_encode_rtp(&channel->rtp,
                                        channel->pt,
                                    (has_more_data == PJ_FALSE ? 1 : 0),
                                        (int)send_len,
                                       rtp_ts_len,
                                        (const void**)&rtphdr,
                                        &rtphdrlen);
        if (status != PJ_SUCCESS) {
            LOGERR_((channel->port.info.name.ptr, status,
                "RTP encode_rtp() error"));
            return status;
        }
        /* When the payload length is zero, we should not send anything,
         * but proceed the rest normally.
         */
         int fu_a_index = 0;
        uint8_t *p_data = (uint8_t *)channel->buf;
        if (reserved_len > 0) {
            #if 1
            if (frame->size > rtp_per_packet_len){
                //fu-a
                if (total_sent == 0){
                    //start
                    p_data[sizeof(pjmedia_rtp_hdr)] =  (nalu & 0x60) | 28;
                    // |S|E|R|  Type   |
                    //S 1 E 0 R 0
                    p_data[sizeof(pjmedia_rtp_hdr)+1] = (1 << 7) | (nalu & 0x1f);
                    fu_a_index += 2;
                }else{
                    if (has_more_data){
                        //end
                        p_data[sizeof(pjmedia_rtp_hdr)] = 28;
                        // |S|E|R|  Type   |
                        //S 0 E 0 R 0
                        p_data[sizeof(pjmedia_rtp_hdr)+1] = (nalu & 0x1f);
                        fu_a_index += 2;
                    }else{                          //end
                        p_data[sizeof(pjmedia_rtp_hdr)] = 28;
                        // |S|E|R|  Type   |
                        //S 0 E 1 R 0
                        p_data[sizeof(pjmedia_rtp_hdr)+1] = (1 << 6) | (nalu & 0x1f);
                        fu_a_index += 2;
                    }
                
                //send_len+=fu_a_index;
            }
            #endif//no -fu-a
            /* Copy RTP header to the beginning of packet */
            pj_memcpy(channel->buf, rtphdr, sizeof(pjmedia_rtp_hdr));
            //copy data
            pj_memcpy(channel->buf + fu_a_index + sizeof(pjmedia_rtp_hdr), data +total_sent + data_start_index, send_len+fu_a_index);
 
            if (stream->transport == NULL){
                break;
            }
            /* Send the RTP packet to the transport. */
            status = pjmedia_transport_send_rtp(stream->transport,
                            (char*)channel->buf,
                            send_len +
                                sizeof(pjmedia_rtp_hdr) +fu_a_index);
            if (status != PJ_SUCCESS) {
                if (stream->rtp_tx_err_cnt++ == 0) {
                    LOGERR_((channel->port.info.name.ptr, status,
                         "Error sending RTP"));
                }
                if (stream->rtp_tx_err_cnt > SEND_ERR_COUNT_TO_REPORT) {
                    stream->rtp_tx_err_cnt = 0;
                }
                break;
            }
            pjmedia_rtcp_tx_rtp(&stream->rtcp, (unsigned)send_len);
            //total_sent += frame_out.size;
            pj_thread_sleep(2);//2ms
            pkt_cnt++;
        }
             
        /* Next packets use same timestamp */
        rtp_ts_len = 0; 
         
        reserved_len -= send_len; 
        total_sent += send_len;
        if (reserved_len <= 0){
            break;
        }
     }
       //PJ_PERROR(4,(THIS_FILE, status,  "put_frame len:%d,total_sent:%d", frame->size,total_sent));
    goto ov5000_end;
   #endif
    
  ov5000_end:
#if TRACE_RC
    /* Trace log for rate control */
    {
        pj_timestamp end_time;
        unsigned total_sleep;
 
        pj_get_timestamp(&end_time);
        total_sleep = pj_elapsed_msec(&initial_time, &end_time);
        PJ_LOG(5, (stream->name.ptr, "total pkt=%d size=%d sleep=%d",
                   pkt_cnt, total_sent, total_sleep));
 
        if (stream->tx_start.u64 == 0)
            stream->tx_start = initial_time;
        stream->tx_end = end_time;
        stream->rc_total_pkt += pkt_cnt;
        stream->rc_total_sleep += total_sleep;
        stream->rc_total_img++;
    }
#endif


其他修改:

1
2
3
4
5
6
7
vid_port_destroy
 
    #if PJMEDIA_VIDEO_DEV_HAS_OV5000
    //free ringbuffer  
    ringfree();
    //add end.
    #endif

呱牛笔记

-------------------广告线---------------
项目、合作,欢迎勾搭,邮箱:promall@qq.com


本文为呱牛笔记原创文章,转载无需和我联系,但请注明来自呱牛笔记 ,it3q.com

请先登录后发表评论
  • 最新评论
  • 总共0条评论