#include #include /* 序号 字段 字节 说明 * 0 标识码 2 0xFFE1 ~ 0xFFEF * 1 数据长度 2 字段长度,不包括标识码,但包括本字段。JPEG标志定义,解码器可以根据长度跳过此标识段 * 2 视频信息 1 码流格式, H264:0x01 * 3 视频帧率 1 每秒帧数,如25表示25FPS * 4 保留信息 6 预留字段,默认都为0x00 * 5 视频数据长度 2 视频数据字段长度,包括本字段 * 6 视频数据 n 视频数据字节数 = (视频数据长度 - 2) * * 说明:每个字段(0xFFEX)仅支持填充(65535 - 12)字节数据。该封装协议支持最大填充(65523 * 15)字节数据 */ #define PROCOTOL_HEAD_SIZE 14 #define SECTIONS_NUMS 9 #define SECTIONS_SIZE (65535 - 12) #define APP1 0xFFE7 static unsigned char* fill_protocol_head(unsigned char* out, unsigned short id, unsigned char fps, unsigned short video_len) { unsigned char* pout = out; unsigned short val; // Identification code val = id; *pout++ = (unsigned char)((val >> 8) & 0xFF); *pout++ = (unsigned char)(val & 0xFF); // Data length val = 12 + video_len; *pout++ = (unsigned char)((val >> 8) & 0xFF); *pout++ = (unsigned char)(val & 0xFF); // Video information *pout++ = (unsigned char)0x01; // 0x01: H264 // FPS *pout++ = fps; // Reserve memset(pout, 0, 6); pout += 6; // Video data length val = video_len + 2; *pout++ = (unsigned char)((val >> 8) & 0xFF); *pout++ = (unsigned char)(val & 0xFF); return pout; } static unsigned int merge_h264_to_jpeg(unsigned char* out, unsigned char* frame_h264, unsigned int size_h264, unsigned short fps) { unsigned int size; unsigned short i; unsigned char* pout = out; unsigned char* psrc = frame_h264; unsigned short id = (unsigned short)APP1; unsigned short sec_size = SECTIONS_SIZE; unsigned short sections = size_h264 / sec_size; unsigned short remaining = size_h264 % sec_size; size = 0; for (i = 0; i < sections; i++) { pout = fill_protocol_head(pout, id, fps, sec_size); // fill frame data memcpy(pout, psrc, sec_size); pout += sec_size; psrc += sec_size; id += 1; size += (sec_size + PROCOTOL_HEAD_SIZE); } if (remaining) { pout = fill_protocol_head(pout, id, fps, remaining); // fill frame data memcpy(pout, psrc, remaining); pout += remaining; id += 1; size += (remaining + PROCOTOL_HEAD_SIZE); } //printf("merge h264 size(%u) to jpeg ok.\n", size); return size; } static unsigned char* refactoring_jpeg(unsigned char* frame_jpeg, unsigned int size_jpeg, unsigned int len_jpeg, unsigned int size_h264) { unsigned char* ph264_start = NULL; unsigned char* pjpeg_old = NULL; unsigned char* pjpeg_new = NULL; unsigned int size; unsigned int move_size; unsigned int h264_pack_size, total_pack_size; unsigned int sections_num; sections_num = (size_h264 / SECTIONS_SIZE); if (size_h264 % SECTIONS_SIZE) { sections_num += 1; } h264_pack_size = (sections_num * PROCOTOL_HEAD_SIZE) + size_h264; total_pack_size = h264_pack_size + size_jpeg; if ((total_pack_size > len_jpeg) || (sections_num > SECTIONS_NUMS)) { printf("[ERROR] H264 frame is too large, I will drop it!\n"); return NULL; } ph264_start = frame_jpeg; // skip 0xFFD8 and 0xFFE0 ph264_start += 4; // skip APP0 字段 size = (ph264_start[0] << 8) & 0xFF00; size += (ph264_start[1] & 0xFF); ph264_start += size; // Move the data after 'APP0 field' and leave space for H264 pjpeg_old = ph264_start; pjpeg_new = (pjpeg_old + h264_pack_size); move_size = size_jpeg - 4 - size; memmove(pjpeg_new, pjpeg_old, move_size); return ph264_start; } /* @brief Package a frame of H264 into mjpeg * * @param [in, out] frame_jpeg Mjpeg frame buffer address * @param [in] size_jpeg Mjpeg frame size * @param [in] len_jpeg Mjpeg frame buffer size * @param [in] frame_h264 H264 frame buffer address * @param [in] size_h264 H264 frame size * @param [in] fps H264 FPS * * @return The total length of valid data in frame_jpeg. */ unsigned int pack_h264_to_jpeg(unsigned char* frame_jpeg, unsigned int size_jpeg, unsigned int len_jpeg, unsigned char* frame_h264, unsigned int size_h264, unsigned int fps) { unsigned int ret, total_size; unsigned char* ph264 = NULL; total_size = size_jpeg; ph264 = refactoring_jpeg(frame_jpeg, size_jpeg, len_jpeg, size_h264); if (ph264 == NULL) { return total_size; } ret = merge_h264_to_jpeg(ph264, frame_h264, size_h264, (unsigned short)fps); total_size += ret; return total_size; } #if 0 static void dexdump(const unsigned char* str, unsigned int size) { unsigned int i; for (i = 0; i < size; i++) { printf("0x%02X, ", str[i]); } printf("\n"); } int main(unsigned int argc, unsigned char* argv[]) { unsigned char frame_jpeg[2048] = {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0xC5, 0x00, 0x28, 0x1C, 0x1E, 0x23, 0x1E, 0x19, 0x28, 0x23, 0x21, 0x23, 0x2D, 0x2B, 0x28, 0x30, 0x3C}; unsigned char frame_h264[61]; unsigned char i; unsigned int size; for (i = 0; i < sizeof(frame_h264); i++) { frame_h264[i] = i; } size = pack_h264_to_jpeg(frame_jpeg, 40, 1024, frame_h264, sizeof(frame_h264), 15); dexdump(frame_jpeg, size); return 0; } #endif