#include "flv-writer.h" #include "flv-header.h" #include "flv-proto.h" #include #include #include #include #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); }