live555實現共享記憶體視訊直播
在上節的基於FIFO傳輸的例子上修改,實現了基於共享記憶體的rtsp傳輸,
結構體share_mem儲存接收到的資料長度和資料,在init函式裡實現了訊號量和共享記憶體的初始化
SendH264File不再呼叫SendH264Data,直接把資料和長度寫進共享記憶體。
/********************************************************************
filename: RTSPStream.cpp
*********************************************************************/
#include "RTSPStream.hh"
#ifdef WIN32
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/sem.h>
#endif
#define FIFO_NAME "/tmp/H264_fifo"
#define BUFFERSIZE PIPE_BUF
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
typedef struct share_mem
{
int len;
unsigned char data[1024*512];
}share_mem;
CRTSPStream::CRTSPStream(void)
{
}
CRTSPStream::~CRTSPStream(void)
{
}
bool CRTSPStream::Init()
{
/*if(access(FIFO_NAME,F_OK) == -1)
{
int res = mkfifo(FIFO_NAME,0777);
if(res != 0)
{
printf("[RTSPStream] Create fifo failed.\n");
return false;
}
printf("PIPE_BUF:%d\n",PIPE_BUF);
}*/
int shmid;
printf("sizeof(struct share_mem) : %d",sizeof(struct share_mem));
m_sem_id = semget((key_t)3443, 1, 0666 | IPC_CREAT);
union semun sem_union;
sem_union.val = 1;
if(semctl(m_sem_id, 0, SETVAL, sem_union) == -1)
perror("semctl error");
shmid = shmget(SHARE_MEM_ID,sizeof(share_mem),( IPC_CREAT|0666));;
if(shmid < 0)
perror("shmget error");
pch_shmem = ( struct share_mem* )shmat(shmid,( const void* )0,0 );
if(pch_shmem == (void *)-1)
{
perror("shmem error\n");
}
return true;
}
void CRTSPStream::Uninit()
{
}
bool CRTSPStream::SendH264File(const char *pFileName)
{
if(pFileName == NULL)
{
return false;
}
FILE *fp = fopen(pFileName, "rb");
if(!fp)
{
printf("[RTSPStream] error:open file %s failed!",pFileName);
}
fseek(fp, 0, SEEK_SET);
//unsigned char *buffer = new unsigned char[FILEBUFSIZE];
int pos = 0;
while(1)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(m_sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
return 0;
}
pch_shmem->len = fread(pch_shmem->data, sizeof(unsigned char), 1024*512, fp);
//struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(m_sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
return 0;
}
if(pch_shmem->len<=0)
{
perror("readlen \n");
break;
}
printf("readlen:%d,pos:%d\n",pch_shmem->len,pos);
//int writelen = SendH264Data(pch_shmem,readlen);
/* if(writelen<=0)
{
printf("writelen %d\n",writelen);
perror("a\n");
break;
}
*/
//memcpy(buffer,buffer+writelen,readlen-writelen);
//memcpy(buffer,buffer+writelen,readlen-writelen);
//pos = readlen-writelen;
// printf("writelen:%d,readlen-writelen:%d\n",writelen,pos);
mSleep(100);
//mSleep(100);
sleep(2);
}
fclose(fp);
//delete[] buffer;
return true;
}
int CRTSPStream::SendH264Data(const unsigned char *data,unsigned int size)
{
if(data == NULL)
{
printf("data is 0\n");
return 0;
}
// open pipe with non_block mode
int pipe_fd = open(FIFO_NAME, O_WRONLY);
printf("[RTSPStream] open fifo result = [%d]\n",pipe_fd);
if(pipe_fd == -1)
{
perror("open failed\n");
return 0;
}
int send_size = 0;
int remain_size = size;
while(send_size < size)
{
int data_len = (remain_size<BUFFERSIZE) ? remain_size : BUFFERSIZE;
int len = write(pipe_fd,data+send_size,data_len);
printf("data_len:%d,send_size:%d\n",data_len,send_size);
if(len == -1)
{
static int resend_conut = 0;
if(errno == EAGAIN && ++resend_conut<=3)
{
printf("[RTSPStream] write fifo error,resend..\n");
continue;
}
resend_conut = 0;
printf("[RTSPStream] write fifo error,errorcode[%d],send_size[%d]\n",errno,send_size);
break;
}
else
{
send_size+= len;
remain_size-= len;
}
//sleep(8);
}
close(pipe_fd);
//printf("[RTSPStream] SendH264Data datalen[%d], sendsize = [%d]\n",size,send_size);
return 0;
}
#if 0
bool CRTSPStream::SendH264File(const char *pFileName)
{
if(pFileName == NULL)
{
return false;
}
FILE *fp = fopen(pFileName, "rb");
if(!fp)
{
printf("[RTSPStream] error:open file %s failed!",pFileName);
}
fseek(fp, 0, SEEK_SET);
unsigned char *buffer = new unsigned char[FILEBUFSIZE];
int pos = 0;
while(1)
{
int readlen = fread(buffer, sizeof(unsigned char), FILEBUFSIZE, fp);
if(readlen<=0)
{
perror("readlen \n");
break;
}
printf("readlen:%d,pos:%d\n",readlen,pos);
//readlen+=pos;
pos += readlen;
int writelen = SendH264Data(buffer,readlen);
/* if(writelen<=0)
{
printf("writelen %d\n",writelen);
perror("a\n");
break;
}
*/
//memcpy(buffer,buffer+writelen,readlen-writelen);
//memcpy(buffer,buffer+writelen,readlen-writelen);
//pos = readlen-writelen;
// printf("writelen:%d,readlen-writelen:%d\n",writelen,pos);
mSleep(25);
}
fclose(fp);
delete[] buffer;
return true;
}
#endif
// 傳送H264資料幀
#if 0
int CRTSPStream::SendH264Data(const unsigned char *data,unsigned int size)
{
if(data == NULL)
{
printf("data is 0\n");
return 0;
}
// open pipe with non_block mode
int pipe_fd = open(FIFO_NAME, O_WRONLY);
printf("[RTSPStream] open fifo result = [%d]\n",pipe_fd);
if(pipe_fd == -1)
{
perror("open failed\n");
return 0;
}
int send_size = 0;
int remain_size = size;
while(send_size < size)
{
int data_len = (remain_size<BUFFERSIZE) ? remain_size : BUFFERSIZE;
int len = write(pipe_fd,data+send_size,data_len);
printf("data_len:%d,send_size:%d\n",data_len,send_size);
if(len == -1)
{
static int resend_conut = 0;
if(errno == EAGAIN && ++resend_conut<=3)
{
printf("[RTSPStream] write fifo error,resend..\n");
continue;
}
resend_conut = 0;
printf("[RTSPStream] write fifo error,errorcode[%d],send_size[%d]\n",errno,send_size);
break;
}
else
{
send_size+= len;
remain_size-= len;
}
//sleep(8);
}
close(pipe_fd);
//printf("[RTSPStream] SendH264Data datalen[%d], sendsize = [%d]\n",size,send_size);
return 0;
}
#endif
對於rtsp server的修改如下
WW_H264VideoSource用於獲取訊號量和共享記憶體
主要的修改集中在GetFrameData,資料傳給fTo地址的記憶體區域,長度傳給全域性變數fFrameSize,和FIFO模式一樣
#include "WW_H264VideoSource.hh"
#include "RTSPStream.hh"
#include <stdio.h>
#ifdef WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <sys/shm.h>
#include <sys/sem.h>
#endif
#define FIFO_NAME "/tmp/H264_fifo"
#define BUFFER_SIZE PIPE_BUF
//#define REV_BUF_SIZE (1024*1024)
#define REV_BUF_SIZE (1024*1024)
#ifdef WIN32
#define mSleep(ms) Sleep(ms)
#else
#define mSleep(ms) usleep(ms*1000)
#endif
union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
};
typedef struct share_mem
{
int len;
unsigned char data[1024*1024];
}share_mem;
WW_H264VideoSource::WW_H264VideoSource(UsageEnvironment & env) :
FramedSource(env),
m_pToken(0),
m_pFrameBuffer(0),
m_hFifo(0)
{
/* m_hFifo = open(FIFO_NAME,O_RDONLY|O_NONBLOCK);
printf("[MEDIA SERVER] open fifo result = [%d],PIPE_BUF=%d\n",m_hFifo,PIPE_BUF);
if(m_hFifo == -1)
{
perror("m_hFifo\n");
return;
}
*/
m_pFrameBuffer = new char[REV_BUF_SIZE];
if(m_pFrameBuffer == NULL)
{
perror("m_hFifo\n");
printf("[MEDIA SERVER] error malloc data buffer failed\n");
return;
}
memset(m_pFrameBuffer,0,REV_BUF_SIZE);
m_sem_id = semget((key_t)3443, 0, 0);
int shmid;
shmid = shmget(SHARE_MEM_ID,0,0);
if(shmid == -1)
{
perror("shmem error ");
}
pch_shmem = ( struct share_mem* )shmat( shmid,( const void* )0,0 );
printf("success\n");
}
WW_H264VideoSource::~WW_H264VideoSource(void)
{
/* if(m_hFifo)
{
::close(m_hFifo);
}
*/
envir().taskScheduler().unscheduleDelayedTask(m_pToken);
if(m_pFrameBuffer)
{
delete[] m_pFrameBuffer;
m_pFrameBuffer = NULL;
}
printf("[MEDIA SERVER] rtsp connection closed\n");
}
void WW_H264VideoSource::doGetNextFrame()
{
// 根據 fps,計算等待時間
double delay = 1000.0 / (FRAME_PER_SEC * 2); // ms
int to_delay = delay * 1000; // us
m_pToken = envir().taskScheduler().scheduleDelayedTask(to_delay, getNextFrame, this);
}
unsigned int WW_H264VideoSource::maxFrameSize() const
{
return 1024*1024;
}
void WW_H264VideoSource::getNextFrame(void * ptr)
{
((WW_H264VideoSource *)ptr)->GetFrameData();
}
void WW_H264VideoSource::GetFrameData()
{
gettimeofday(&fPresentationTime, 0);
//printf("get frame\n");
// fFrameSize = 1024*512;
int len = 0;
unsigned char buffer[BUFFER_SIZE] = {0};
/* while((len = read(m_hFifo,buffer,BUFFER_SIZE))>0)
{
//printf("len is %d\n",len);
memcpy(m_pFrameBuffer+fFrameSize,buffer,len);
fFrameSize+=len;
//sleep(5);
}
printf("[MEDIA SERVER] GetFrameData len = [%d],fMaxSize = [%d]\n",fFrameSize,fMaxSize);
*/
// fill frame data
//memcpy(fTo,m_pFrameBuffer,fFrameSize);
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(m_sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed\n");
//return 0;
}
memcpy(m_pFrameBuffer,pch_shmem->data,pch_shmem->len);
printf("len:%d,fMaxSize:%d\n",pch_shmem->len,fMaxSize);
fFrameSize = pch_shmem->len;
memcpy(fTo,m_pFrameBuffer,fFrameSize);
//FILE *fp = fopen("123.264", "wb");
//fwrite(pch_shmem,1,1024*1024,fp);
//fclose(fp);
// struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;//V()
sem_b.sem_flg = SEM_UNDO;
if(semop(m_sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed\n");
//return 0;
}
//printf("fTo,pch_shmem\n");
/* if (fFrameSize > fMaxSize)
{
fNumTruncatedBytes = fFrameSize - fMaxSize;
fFrameSize = fMaxSize;
}
else
{
fNumTruncatedBytes = 0;
}
*/
afterGetting(this);
}
編譯後,既可播放,檔案讀取播放一切正常,用於攝像頭資料實時傳輸 偶爾出現花屏,據分析是攝像頭一幀資料較小,而rtsp傳送給客戶端沒有加上訊號量保護,對c++不熟悉,就不再研究了,以後會用fenice實現rtsp
相關文章
- 程式間通訊——基於共享記憶體和訊號量實現共享佇列記憶體佇列
- php實現共享記憶體程式通訊函式之_shmPHP記憶體函式
- 程式間通訊---共享記憶體記憶體
- Linux共享記憶體的核心實現Linux記憶體
- 視訊直播的實現
- 資料庫實現原理#6(共享記憶體)資料庫記憶體
- 程式間通訊之共享記憶體記憶體
- 程序間通訊(3)-共享記憶體記憶體
- 共享記憶體記憶體
- system-v IPC共享記憶體通訊記憶體
- 有管理共享記憶體設計方法的具體實現記憶體
- Golang 共享記憶體Golang記憶體
- POSIX共享記憶體記憶體
- oracle 共享記憶體Oracle記憶體
- POSIX 共享記憶體記憶體
- 訊號量、訊息佇列、共享記憶體複習佇列記憶體
- Linux程式間通訊之共享記憶體Linux記憶體
- Linux程式間通訊——使用共享記憶體Linux記憶體
- 實現共享記憶體的又一方法 (轉)記憶體
- OpenResty 和 Nginx 的共享記憶體區是如何消耗實體記憶體的RESTNginx記憶體
- linux程式間的通訊(C): 共享記憶體Linux記憶體
- 程式-IPC 共享記憶體和訊息佇列 (三)記憶體佇列
- nginx共享記憶體分析Nginx記憶體
- QT之共享記憶體QT記憶體
- 共享記憶體函式記憶體函式
- shmget() -- 建立共享記憶體記憶體
- SGA與共享記憶體記憶體
- linux共享記憶體Linux記憶體
- 給PHP開啟shmop擴充套件實現共享記憶體PHP套件記憶體
- 自動共享記憶體管理 自動記憶體管理 手工記憶體管理記憶體
- Linux 程式間通訊之System V 共享記憶體Linux記憶體
- 顯示卡的視訊記憶體是什麼?記憶體
- Qt共享記憶體QSharedMemoryQT記憶體
- Linux共享記憶體(二)Linux記憶體
- 修改/dev/shm共享記憶體dev記憶體
- 共享記憶體分段問題記憶體
- SGA與共享記憶體2記憶體
- 顯示卡視訊記憶體2G和4G的區別 視訊記憶體越大效能越好嗎?記憶體