136 lines
2.9 KiB
C
136 lines
2.9 KiB
C
|
#include "flv-reader.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_reader_t
|
||
|
{
|
||
|
FILE* fp;
|
||
|
int (*read)(void* param, void* buf, int len);
|
||
|
void* param;
|
||
|
};
|
||
|
|
||
|
static int flv_read_header(struct flv_reader_t* flv)
|
||
|
{
|
||
|
uint32_t sz;
|
||
|
uint8_t data[FLV_HEADER_SIZE];
|
||
|
struct flv_header_t h;
|
||
|
int n;
|
||
|
|
||
|
if (FLV_HEADER_SIZE != flv->read(flv->param, data, FLV_HEADER_SIZE))
|
||
|
return -1;
|
||
|
|
||
|
if(FLV_HEADER_SIZE != flv_header_read(&h, data, FLV_HEADER_SIZE))
|
||
|
return -1;
|
||
|
|
||
|
assert(h.offset >= FLV_HEADER_SIZE && h.offset < FLV_HEADER_SIZE + 4096);
|
||
|
for(n = (int)(h.offset - FLV_HEADER_SIZE); n > 0 && n < 4096; n -= sizeof(data))
|
||
|
flv->read(flv->param, data, n >= sizeof(data) ? sizeof(data) : n); // skip
|
||
|
|
||
|
// PreviousTagSize0
|
||
|
if (4 != flv->read(flv->param, data, 4))
|
||
|
return -1;
|
||
|
|
||
|
flv_tag_size_read(data, 4, &sz);
|
||
|
assert(0 == sz);
|
||
|
return 0 == sz ? 0 : -1;
|
||
|
}
|
||
|
|
||
|
static int file_read(void* param, void* buf, int len)
|
||
|
{
|
||
|
return (int)fread(buf, 1, len, (FILE*)param);
|
||
|
}
|
||
|
|
||
|
void* flv_reader_create(const char* file)
|
||
|
{
|
||
|
FILE* fp;
|
||
|
struct flv_reader_t* flv;
|
||
|
fp = fopen(file, "rb");
|
||
|
if (!fp)
|
||
|
return NULL;
|
||
|
|
||
|
flv = flv_reader_create2(file_read, fp);
|
||
|
if (!flv)
|
||
|
{
|
||
|
fclose(fp);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
flv->fp = fp;
|
||
|
return flv;
|
||
|
}
|
||
|
|
||
|
void* flv_reader_create2(int (*read)(void* param, void* buf, int len), void* param)
|
||
|
{
|
||
|
struct flv_reader_t* flv;
|
||
|
flv = (struct flv_reader_t*)calloc(1, sizeof(*flv));
|
||
|
if (!flv)
|
||
|
return NULL;
|
||
|
|
||
|
flv->read = read;
|
||
|
flv->param = param;
|
||
|
if (0 != flv_read_header(flv))
|
||
|
{
|
||
|
flv_reader_destroy(flv);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return flv;
|
||
|
}
|
||
|
|
||
|
void flv_reader_destroy(void* p)
|
||
|
{
|
||
|
struct flv_reader_t* flv;
|
||
|
flv = (struct flv_reader_t*)p;
|
||
|
if (NULL != flv)
|
||
|
{
|
||
|
if (flv->fp)
|
||
|
fclose(flv->fp);
|
||
|
free(flv);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int flv_reader_read(void* p, int* tagtype, uint32_t* timestamp, size_t* taglen, void* buffer, size_t bytes)
|
||
|
{
|
||
|
int r;
|
||
|
uint32_t sz;
|
||
|
uint8_t header[FLV_TAG_HEADER_SIZE];
|
||
|
struct flv_tag_header_t tag;
|
||
|
struct flv_reader_t* flv;
|
||
|
flv = (struct flv_reader_t*)p;
|
||
|
|
||
|
r = flv->read(flv->param, &header, FLV_TAG_HEADER_SIZE);
|
||
|
if (r != FLV_TAG_HEADER_SIZE)
|
||
|
return r < 0 ? r : 0; // 0-EOF
|
||
|
|
||
|
if (FLV_TAG_HEADER_SIZE != flv_tag_header_read(&tag, header, FLV_TAG_HEADER_SIZE))
|
||
|
return -1;
|
||
|
|
||
|
if (bytes < tag.size)
|
||
|
return -1;
|
||
|
|
||
|
// FLV stream
|
||
|
r = flv->read(flv->param, buffer, tag.size);
|
||
|
if(tag.size != (uint32_t)r)
|
||
|
return r < 0 ? r : 0; // 0-EOF
|
||
|
|
||
|
// PreviousTagSizeN
|
||
|
r = flv->read(flv->param, header, 4);
|
||
|
if (4 != r)
|
||
|
return r < 0 ? r : 0; // 0-EOF
|
||
|
|
||
|
*taglen = tag.size;
|
||
|
*tagtype = tag.type;
|
||
|
*timestamp = tag.timestamp;
|
||
|
flv_tag_size_read(header, 4, &sz);
|
||
|
assert(0 == tag.streamId); // StreamID Always 0
|
||
|
assert(sz == tag.size + FLV_TAG_HEADER_SIZE);
|
||
|
return (sz == tag.size + FLV_TAG_HEADER_SIZE) ? 1 : -1;
|
||
|
}
|