读取本地文件,并逐帧读取:
onReadThread():
void RtspVideo::onReadThread()
{
// 解码参数
char *virInBuf = new char[MAX_DECODER_INPUT_BUFFER_SIZE];
//初始化文件读入buf
if (init_frame_parser() < 0) {
fprintf(stderr, "Error: init frame parser\n");
}
// find the first SPS,PPS,SEI header -> 读取h264文件头到frmbuf中
int frmlen;
uint8_t * frmbuf;
if ((frmlen = read_one_frame(fpi, &frmbuf, 1)) <= 0) {
fprintf(stderr, "Error: cannot find header\n");
deinit_frame_parser();
}
do {
// read one frame
if ((frmlen = read_one_frame(fpi, &frmbuf, 0)) <= 0) {
break;
}
memcpy(virInBuf, frmbuf + 4, frmlen-4);
{
Poco::Mutex::ScopedLock s(m_bufLock);
MyStruct *stu = new MyStruct();
stu->pData = new char[frmlen-4];
memcpy(stu->pData, virInBuf, frmlen-4);
stu->nLen = frmlen-4;
m_pDataCtrl.push_back(stu);
//OutputDebugStringA("=========================\n");
}
} while (1);
delete[] virInBuf;
}
int read_one_frame(FILE *fp, uint8_t **buf, int header):
int RtspVideo::read_one_frame(FILE *fp, uint8_t **buf, int header)
{
int ustart, uend;
int cstart, cend;
int found;
uint8_t nal_unit_type;
// 从文件中读取一段数据到fbuf缓冲区中,读取的长度是缓冲区最大长度的一半
// fstart==fend : empty
// we keep fstart<=fend. whenever fend goes beyond fbufsz, we move the data back to [0 ...)
int rsz;
if (!end_of_file && fend - fstart < fbufsz / 2) { // fbuf is less than half full
if (fstart > fbufsz / 2) { // move back to [0 ...)
memcpy(fbuf, fbuf + fstart, fend - fstart);
fend -= fstart;
fstart = 0;
}
// fill up to half: fbufsz/2-fend+fstart
rsz = fread(fbuf + fend, 1, fbufsz / 2 - fend + fstart, fp);
if (rsz < (int)(fbufsz / 2 - fend + fstart)) { // end of file
printf("We have read all data from the input file\n");
end_of_file = 1;
}
if (rsz > 0)
fend += rsz;
}
if (fend > fbufsz) {
fprintf(stderr, "Opps: this should never happen!\n");
return -1;
}
// 读取文件头数据
// now either fbuf is half full or it is end of file
if (header) { // find header
// find the first SPS,PPS,SEI header
found = 0;
cstart = cend = -1;
while (find_nal_unit(fbuf + fstart, fend - fstart, &ustart, &uend) > 0) {
nal_unit_type = fbuf[fstart + ustart] & 0x1f;
if (nal_unit_type == (uint8_t)6 || nal_unit_type == (uint8_t)7 || nal_unit_type == (uint8_t)8) {
// SEI, SPS or PPS
if (!found) {
found = 1;
cstart = fstart + ustart-4; // the start of first SPS, PPS or SEI, fbuf[cstart]: 00 00 01
// if (cstart > 0 && !fbuf[cstart - 1])
// cstart--;
}
}
else {
if (found) {
cend = fstart + ustart-4; // the end of header before the following picture slice NAL. fbuf[cend]: 00 00 01
// if (!fbuf[cend - 1]) { // the following picture slice has a long start code 00 00 00 01
// cend--;
// }
break;
}
}
fstart += uend; // now fbuf[fstart] is the first byte of start code of next NAL
}
if (cstart < 0 || cend < 0) {
fprintf(stderr, "Error: cannot find a NAL header.\n");
buf = NULL;
if (!end_of_file)
fprintf(stderr, "You should consider increase fbufsz. Current fbufsz=%d.\n", fbufsz);
return -1;
}
fstart = cend;
// now fbuf[cstart,cend) should contain the first SPS,PPS,SEI header
printf("Header: cstart=%x, cend=%x, length=%d\n", cstart, cend, cend - cstart);
*buf = fbuf + cstart;
return cend - cstart;
}
// 读取一段NALU数据
cstart = cend = -1;
found = 0;
while (find_nal_unit(fbuf + fstart, fend - fstart, &ustart, &uend) > 0) {
nal_unit_type = fbuf[fstart + ustart] & 0x1f;
if (nal_unit_type == (uint8_t)6 || nal_unit_type == (uint8_t)7 || nal_unit_type == (uint8_t)8) {
// SEI, SPS or PPS
if (!found) {
found = 1;
cstart = fstart + ustart - 4 ; // the start of first SPS, PPS or SEI, fbuf[cstart]: 00 00 01
// if (cstart > 0 && !fbuf[cstart - 1])
// cstart--;
cend = fstart + uend;
break;
}
}
else if (nal_unit_type == (uint8_t)1 || nal_unit_type == (uint8_t)5) { // IDR or non-IDR
if (!found) { // no header
cstart = fstart + ustart - 4;
// if (cstart > 0 && !fbuf[cstart - 1])
// cstart--;
}
cend = fstart + uend;
break;
}
cstart = fstart + ustart - 4;
fstart += uend; // now fbuf[fstart] is the first byte of start code of next NAL
}
if (cstart < 0 || cend < 0) {
//printf("No more NALs. Exiting\n");
buf = NULL;
if (!end_of_file)
fprintf(stderr, "You should consider increase fbufsz. Current fbufsz=%d.\n", fbufsz);
return -1;
}
fstart = cend;
*buf = fbuf + cstart;
return cend - cstart+2;
}
int find_nal_unit(uint8_t* buf, int size, int* nal_start, int* nal_end):
/** this function is taken from the h264bitstream library written by Alex Izvorski and Alex Giladi
Find the beginning and end of a NAL (Network Abstraction Layer) unit in a byte buffer containing H264 bitstream data.
@param[in] buf the buffer
@param[in] size the size of the buffer
@param[out] nal_start the beginning offset of the nal
@param[out] nal_end the end offset of the nal
@return the length of the nal, or 0 if did not find start of nal, or -1 if did not find end of nal
*/
int RtspVideo::find_nal_unit(uint8_t* buf, int size, int* nal_start, int* nal_end)
{
if (NULL == buf)
{
return 0;
}
int i;
// find start
*nal_start = 0;
*nal_end = 0;
i = 0;
while ( //( next_bits( 24 ) != 0x000001 && next_bits( 32 ) != 0x00000001 )
//(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) &&
(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01)
)
{
i++; // skip leading zero
if (i + 4 >= size) { return 0; } // did not find nal start
}
// if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) // ( next_bits( 24 ) != 0x000001 )
// {
// i++;
// }
if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01) // ( next_bits( 24 ) != 0x000001 )
{
i++;
}
//if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01) { /* error, should never happen */ return 0; }
//i += 3;
if (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01) { /* error, should never happen */ return 0; }
i += 4;
*nal_start = i;
// while ( //( next_bits( 24 ) != 0x000000 && next_bits( 24 ) != 0x000001 )
// (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0) &&
// (buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0x01)
// )
// {
// i++;
// // FIXME the next line fails when reading a nal that ends exactly at the end of the data
// if (i + 3 >= size) { *nal_end = size; return -1; } // did not find nal end, stream ended first
// }
while ( //( next_bits( 24 ) != 0x000000 && next_bits( 24 ) != 0x000001 )
//(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0) &&
(buf[i] != 0 || buf[i + 1] != 0 || buf[i + 2] != 0 || buf[i + 3] != 0x01)
)
{
i++;
// FIXME the next line fails when reading a nal that ends exactly at the end of the data
if (i + 4 >= size) { *nal_end = size; return -1; } // did not find nal end, stream ended first
}
*nal_end = i;
return (*nal_end - *nal_start);
}