通过信号量和共享内存实现h264码流在不同进程间传输

读写这两个进程需要共享的内存,在头文件中定义,

#define DZY_FRAME_SIZE 300000
#define DZY_FRAME_COUNT 10
typedef struct single_frame
{
    int length;
    char frame[DZY_FRAME_SIZE];
}single_frame;
typedef struct mul_frame
{
    int count;
    int readIdx;
    int writeIdx;
    single_frame frame[DZY_FRAME_COUNT];
}mul_frame;

其中single_frame,存放单个视频帧,mul_frame存放多帧的队列,其中count用来记录帧的数量,readIdx和writeIdx用来记录读帧和写帧的游标,通过结构体实现内存共享,便于操作。

写入进程的共享内存初始化代码

#include 
#include 
int shmid;
mul_frame *shared;//指向shm
sem_t* sem;
void *shm = NULL;//分配的共享内存的原始首地址
shmid = shmget((key_t)1234, sizeof(mul_frame), 0666|IPC_CREAT);
shm = shmat(shmid, 0, 0);
if(shm == (void*)-1)
{
    fprintf(stderr, "shmat failed\n");
}
printf("\nMemory attached at %X\n", (int)shm);
shared = (mul_frame*)shm;
shared->readIdx = 0;
shared->writeIdx = 0;
shared->count = 0;

for(int i =0;iframe[i].length=0;
}
sem = sem_open("mysem", O_CREAT | O_RDWR , 0666, 1);
if (sem == SEM_FAILED)
{
    printf("errno open sem\n");
}

其中共享内存的keyid为1234,用于不同进程间设置同一的keyid,共享内存的大小为sizeof(mul_frame),可以自定义,这在linux上优于命名管道(fifo),因为命名管道
只能缓冲65536bytes,但是命名管道自带同步机制,而共享内存没有,所以需要定义信
号量sem_t* sem,其中mysem为信号量的keyid,同样用于不同进程间共享。

下面是写入进程的共享内存析构代码

//把共享内存从当前进程中分离
if(shmdt((void*)shared) == -1)
{
    fprintf(stderr, "shmdt failed\n");
}
//删除共享内存
if(shmctl(shmid, IPC_RMID, 0) == -1)
{
    fprintf(stderr, "shmctl(IPC_RMID) failed\n");
}
sem_destroy(sem);

读取共享内存的初始化的代码

int shmid;
mul_frame *shared;//指向shm
void *shm = NULL;//分配的共享内存的原始首地址
shmid = shmget((key_t)1234, sizeof(mul_frame), 0666|IPC_CREAT);
if(shmid == -1)
{
    fprintf(stderr, "shmget failed\n");
}
//将共享内存连接到当前进程的地址空间
shm = shmat(shmid, 0, 0);
if(shm == (void*)-1)
{
    fprintf(stderr, "shmat failed\n");
}
printf("\nMemory attached at %X\n", (int)shm);
shared = (mul_frame*)shm;
sem_t* sem;
sem = sem_open("mysem", O_CREAT | O_RDWR , 0666, 0);
if (sem == SEM_FAILED)
{
    printf("errno open sem\n");
}

读取共享内存的代码与写共享内存的代码基本一致,其中sem_open不同,写入的代码中最后一个参数是1,而读取的代码中,最后一个参数是0。

读取共享内存的析构代码,暂略。

下面是写入共享内存的代码

//sem_wait(sem);
//printf("shared->count:%d\n",shared->count);
if(shared->count < DZY_FRAME_COUNT)
{
    shared->frame[shared->readIdx].length = _rxH264Frame->GetFrameSize() - bytesUsed;
    memcpy(shared->frame[shared->readIdx].frame,_rxH264Frame->GetFramePtr() + bytesUsed,shared->frame[shared->readIdx].length);
    shared->readIdx = (shared->readIdx+1)%DZY_FRAME_COUNT;
    shared->count++;
}else
{
    printf("error, shared->count:%d\n",shared->count);
}
sem_post(sem);

下面是读取共享内存的代码

sem_wait(sem);
//printf("shared->count:%d\n",shared->count);
if(shared->count > 0)
{
    *len = shared->frame[shared->writeIdx].length;
    memcpy(buf,shared->frame[shared->writeIdx].frame,*len);
    shared->writeIdx = (shared->writeIdx+1)%DZY_FRAME_COUNT;
    shared->count--;
}else
{
    printf("error, shared->count:%d\n",shared->count);
}
//sem_post(sem);

由于写入共享内存时,是通过网络接收,而读取共享内存是直接保存文件,网络接收的速度明显慢于保存文件,所以只需要在读取的时候加sem_wait,用来等待写入。
另外,通过%DZY_FRAME_COUNT,来实现环形缓冲区的效果。

你可能感兴趣的:(网络,ffmpeg)