Older/MediaServer/libflv/source/flv-writer.c

163 lines
3.7 KiB
C
Raw Normal View History

2024-10-01 00:12:57 +08:00
#include "flv-writer.h"
#include "flv-header.h"
#include "flv-proto.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#define FLV_HEADER_SIZE 9 // DataOffset included
#define FLV_TAG_HEADER_SIZE 11 // StreamID included
struct flv_writer_t
{
FILE* fp;
flv_writer_onwrite write;
void* param;
};
static int flv_write_header(int audio, int video, struct flv_writer_t* flv)
{
struct flv_vec_t vec[1];
uint8_t header[FLV_HEADER_SIZE + 4];
flv_header_write(audio, video, header, FLV_HEADER_SIZE);
flv_tag_size_write(header + FLV_HEADER_SIZE, 4, 0); // PreviousTagSize0(Always 0)
vec[0].ptr = header;
vec[0].len = sizeof(header);
return flv->write(flv->param, vec, 1);
}
static int flv_write_eos(struct flv_writer_t* flv)
{
int n;
uint8_t header[16];
struct flv_video_tag_header_t video;
memset(&video, 0, sizeof(video));
video.codecid = FLV_VIDEO_H264;
video.keyframe = FLV_VIDEO_KEY_FRAME;
video.avpacket = FLV_END_OF_SEQUENCE;
video.cts = 0;
n = flv_video_tag_header_write(&video, header, sizeof(header));
return n > 0 ? flv_writer_input(flv, FLV_TYPE_VIDEO, header, n, 0) : -1;
}
static int file_write(void* param, const struct flv_vec_t* vec, int n)
{
int i;
for(i = 0; i < n; i++)
{
if (vec[i].len != (int)fwrite(vec[i].ptr, 1, vec[i].len, (FILE*)param))
return ferror((FILE*)param);
}
return 0;
}
void* flv_writer_create(const char* file)
{
FILE* fp;
struct flv_writer_t* flv;
fp = fopen(file, "wb");
if (!fp)
return NULL;
flv = flv_writer_create2(1, 1, file_write, fp);
if (!flv)
{
fclose(fp);
return NULL;
}
flv->fp = fp;
return flv;
}
void* flv_writer_create2(int audio, int video, flv_writer_onwrite write, void* param)
{
struct flv_writer_t* flv;
flv = (struct flv_writer_t*)calloc(1, sizeof(*flv));
if (!flv)
return NULL;
flv->write = write;
flv->param = param;
if (0 != flv_write_header(audio, video, flv))
{
flv_writer_destroy(flv);
return NULL;
}
return flv;
}
void flv_writer_destroy(void* p)
{
struct flv_writer_t* flv;
flv = (struct flv_writer_t*)p;
if (NULL != flv)
{
flv_write_eos(flv);
if (flv->fp)
fclose(flv->fp);
free(flv);
}
}
int flv_writer_input(void* p, int type, const void* data, size_t bytes, uint32_t timestamp)
{
uint8_t buf[FLV_TAG_HEADER_SIZE + 4];
struct flv_vec_t vec[3];
struct flv_writer_t* flv;
struct flv_tag_header_t tag;
flv = (struct flv_writer_t*)p;
memset(&tag, 0, sizeof(tag));
tag.size = (int)bytes;
tag.type = (uint8_t)type;
tag.timestamp = timestamp;
flv_tag_header_write(&tag, buf, FLV_TAG_HEADER_SIZE);
flv_tag_size_write(buf + FLV_TAG_HEADER_SIZE, 4, (uint32_t)bytes + FLV_TAG_HEADER_SIZE);
vec[0].ptr = buf; // FLV Tag Header
vec[0].len = FLV_TAG_HEADER_SIZE;
vec[1].ptr = (void*)data;
vec[1].len = (int)bytes;
vec[2].ptr = buf + FLV_TAG_HEADER_SIZE; // TAG size
vec[2].len = 4;
return flv->write(flv->param, vec, 3);
}
int flv_writer_input_v(void* p, int type, const struct flv_vec_t* v, int n, uint32_t timestamp)
{
int i;
uint8_t buf[FLV_TAG_HEADER_SIZE + 4];
struct flv_vec_t vec[8];
struct flv_writer_t* flv;
struct flv_tag_header_t tag;
flv = (struct flv_writer_t*)p;
memset(&tag, 0, sizeof(tag));
tag.size = 0;
tag.type = (uint8_t)type;
tag.timestamp = timestamp;
assert(n + 2 <= sizeof(vec) / sizeof(vec[0]));
for (i = 0; i < n && i + 2 < sizeof(vec)/sizeof(vec[0]); i++)
{
tag.size += v[i].len;
vec[i+1].ptr = v[i].ptr;
vec[i+1].len = v[i].len;
}
vec[0].ptr = buf; // FLV Tag Header
vec[0].len = FLV_TAG_HEADER_SIZE;
vec[n + 1].ptr = buf + FLV_TAG_HEADER_SIZE; // TAG size
vec[n + 1].len = 4;
flv_tag_header_write(&tag, buf, FLV_TAG_HEADER_SIZE);
flv_tag_size_write(buf + FLV_TAG_HEADER_SIZE, 4, (uint32_t)tag.size + FLV_TAG_HEADER_SIZE);
return flv->write(flv->param, vec, n+2);
}