h264bitstream / hevcbitstream (read and write H.264/H.265 video bitstreams)
1、编译安装参考源码包自带的说明文档
h264bitstream-0.2.0/README.md
sudo apt-get install build-essential libtool
autoreconf -i
./configure --prefix=$(pwd)/_install
make
make install
2、例子太啰嗦,精简了一下
h264_analyze.c
/*
* h264bitstream - a library for reading and writing H.264 video
* Copyright (C) 2005-2007 Auroras Entertainment, LLC
*
* Written by Alex Izvorski <aizvorski@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "h264_stream.h"
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define BUFSIZE 32*1024*1024
int main(int argc, char *argv[])
{
FILE* infile;
uint8_t* buf = (uint8_t*)malloc( BUFSIZE );
h264_stream_t* h = h264_new();
if (argc < 2) { return EXIT_FAILURE; }
int opt_verbose = 1;
int opt_probe = 0;
infile = fopen(argv[1], "rb");
if (infile == NULL) { fprintf( stderr, "!! Error: could not open file: %s \n", strerror(errno)); exit(EXIT_FAILURE); }
if (h264_dbgfile == NULL) { h264_dbgfile = stdout; }
size_t rsz = 0;
size_t sz = 0;
int64_t off = 0;
uint8_t* p = buf;
int nal_start, nal_end;
while (1)
{
rsz = fread(buf + sz, 1, BUFSIZE - sz, infile);
if (rsz == 0)
{
if (ferror(infile)) { fprintf( stderr, "!! Error: read failed: %s \n", strerror(errno)); break; }
break; // if (feof(infile))
}
sz += rsz;
while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0)
{
if ( opt_verbose > 0 )
{
fprintf( h264_dbgfile, "!! Found NAL at offset %lld , size %lld \n",
(long long int)(off + (p - buf) + nal_start),
(long long int)(nal_end - nal_start) );
}
p += nal_start;
read_debug_nal_unit(h, p, nal_end - nal_start);
if ( opt_probe && h->nal->nal_unit_type == NAL_UNIT_TYPE_SPS )
{
// print codec parameter, per RFC 6381.
int constraint_byte = h->sps->constraint_set0_flag << 7;
constraint_byte = h->sps->constraint_set1_flag << 6;
constraint_byte = h->sps->constraint_set2_flag << 5;
constraint_byte = h->sps->constraint_set3_flag << 4;
constraint_byte = h->sps->constraint_set4_flag << 3;
constraint_byte = h->sps->constraint_set4_flag << 3;
fprintf( h264_dbgfile, "codec: avc1.%02X%02X%02X\n",h->sps->profile_idc, constraint_byte, h->sps->level_idc );
// TODO: add more, move to h264_stream (?)
break; // we've seen enough, bailing out.
}
if ( opt_verbose > 0 )
{
}
p += (nal_end - nal_start);
sz -= nal_end;
}
// if no NALs found in buffer, discard it
if (p == buf)
{
fprintf( stderr, "!! Did not find any NALs between offset %lld , size %lld , discarding \n",
(long long int)off,
(long long int)off + sz);
p = buf + sz;
sz = 0;
}
memmove(buf, p, sz);
off += p - buf;
p = buf;
}
h264_free(h);
free(buf);
fclose(h264_dbgfile);
fclose(infile);
return 0;
}
编译
gcc h264_analyze.c -o h264_analyze -I $(pwd)/h264bitstream/include/h264bitstream -L $(pwd)/h264bitstream/lib -lh264bitstream
添加库文件环境变量
export LD_LIBRARY_PATH=$(pwd)/h264bitstream/lib:$LD_LIBRARY_PATH
运行
./h264_analyze JM_cqm_cabac.264
3、封装了个函数,方便集成
int get_h264_nalu(uint8_t* buf, size_t sz)
main.c
/*
* h264bitstream - a library for reading and writing H.264 video
* Copyright (C) 2005-2007 Auroras Entertainment, LLC
*
* Written by Alex Izvorski <aizvorski@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "h264_stream.h"
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define BUFSIZE 1024*1024
void h264_nalu_cb(uint8_t* p,size_t sz)
{
printf("h264 payload %x %x %x %x %x\n",p[0],p[1],p[2],p[3],p[4]);
}
int get_h264_nalu(uint8_t* buf, size_t sz)
{
h264_stream_t* h = h264_new();
uint8_t* p = buf;
int nal_start, nal_end;
int n = 0;
while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0)
{
printf("!! Found NAL at offset %lld , size %lld \n",
(long long int)((p - buf) + nal_start),
(long long int)(nal_end - nal_start) );
//export nalu data
//printf("h264 payload %x %x %x %x %x\n",p[0],p[1],p[2],p[3],p[4]);
char str[32];
sprintf(str,"./h264_nalu_frame/test%d.264",n);
FILE *fp = fopen(str, "a+b");
if(fp)
{
fwrite(p, nal_end, 1, fp);
fclose(fp);
fp = NULL;
}
n++;
h264_nalu_cb(p, nal_end);
//debug
p += nal_start;
//read_debug_nal_unit(h, p, nal_end - nal_start);
//next frame
p += (nal_end - nal_start);
sz -= nal_end;
}
h264_free(h);
return 0;
}
int main(int argc, char *argv[])
{
uint8_t* buf = (uint8_t*)malloc( BUFSIZE );
FILE* infile = fopen("test0.264", "rb");
fread(buf,1,BUFSIZE,infile);
get_h264_nalu(buf, BUFSIZE);
fclose(infile);
free(buf);
return 0;
}
还是三步走
gcc main.c -o main -I $(pwd)/h264bitstream/include/h264bitstream -L $(pwd)/h264bitstream/lib -lh264bitstream
export LD_LIBRARY_PATH=$(pwd)/h264bitstream/lib:$LD_LIBRARY_PATH
./main
解析个 sps + pps + i + p*n
dong@ubuntu:~/doing/h264bitstream_demo$ ./build.sh
dong@ubuntu:~/doing/h264bitstream_demo$ ./main
!! Found NAL at offset 4 , size 15
h264 payload 0 0 0 1 67
!! Found NAL at offset 23 , size 4
h264 payload 0 0 0 1 68
!! Found NAL at offset 31 , size 23637
h264 payload 0 0 0 1 65
!! Found NAL at offset 23672 , size 6052
h264 payload 0 0 0 1 41
!! Found NAL at offset 29728 , size 15796
h264 payload 0 0 0 1 41
!! Found NAL at offset 45528 , size 16669
h264 payload 0 0 0 1 41
!! Found NAL at offset 62201 , size 14952
h264 payload 0 0 0 1 41
!! Found NAL at offset 77157 , size 14291
h264 payload 0 0 0 1 41
!! Found NAL at offset 91452 , size 14913
h264 payload 0 0 0 1 41
!! Found NAL at offset 106369 , size 14420
h264 payload 0 0 0 1 41
!! Found NAL at offset 120793 , size 14316
h264 payload 0 0 0 1 41
!! Found NAL at offset 135113 , size 16304
h264 payload 0 0 0 1 41
!! Found NAL at offset 151421 , size 14216
h264 payload 0 0 0 1 41
!! Found NAL at offset 165641 , size 16108
h264 payload 0 0 0 1 41
!! Found NAL at offset 181753 , size 14348
h264 payload 0 0 0 1 41
!! Found NAL at offset 196105 , size 16092
h264 payload 0 0 0 1 41
!! Found NAL at offset 212201 , size 14529
h264 payload 0 0 0 1 41
!! Found NAL at offset 226734 , size 16852
h264 payload 0 0 0 1 41
!! Found NAL at offset 243590 , size 14098
h264 payload 0 0 0 1 41
!! Found NAL at offset 257692 , size 16018
h264 payload 0 0 0 1 41
!! Found NAL at offset 273714 , size 14647
h264 payload 0 0 0 1 41
!! Found NAL at offset 288365 , size 14792
h264 payload 0 0 0 1 41
!! Found NAL at offset 303161 , size 13929
h264 payload 0 0 0 1 41
!! Found NAL at offset 317094 , size 19153
h264 payload 0 0 0 1 41
!! Found NAL at offset 336251 , size 13545
h264 payload 0 0 0 1 41
!! Found NAL at offset 349800 , size 19024
h264 payload 0 0 0 1 41
!! Found NAL at offset 368828 , size 14569
h264 payload 0 0 0 1 41
!! Found NAL at offset 383401 , size 13160
h264 payload 0 0 0 1 41
!! Found NAL at offset 396565 , size 19309
h264 payload 0 0 0 1 41
!! Found NAL at offset 415878 , size 13847
h264 payload 0 0 0 1 41
!! Found NAL at offset 429729 , size 13841
h264 payload 0 0 0 1 41
!! Found NAL at offset 443574 , size 20354
h264 payload 0 0 0 1 41
dong@ubuntu:~/doing/h264bitstream_demo$
4、去掉00 00 00 01起始码
这两行换个顺序
h264_nalu_cb(p, nal_end);
p += nal_start;
main.c
/*
* h264bitstream - a library for reading and writing H.264 video
* Copyright (C) 2005-2007 Auroras Entertainment, LLC
*
* Written by Alex Izvorski <aizvorski@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "h264_stream.h"
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#define BUFSIZE 1024*1024
void h264_nalu_cb(uint8_t* p,size_t sz)
{
printf("h264 payload %x %x %x %x %x\n",p[0],p[1],p[2],p[3],p[4]);
}
int get_h264_nalu(uint8_t* buf, size_t sz)
{
h264_stream_t* h = h264_new();
uint8_t* p = buf;
int nal_start, nal_end;
int n = 0;
while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0)
{
printf("!! Found NAL at offset %lld , size %lld \n",
(long long int)((p - buf) + nal_start),
(long long int)(nal_end - nal_start) );
//printf("h264 payload %x %x %x %x %x\n",p[0],p[1],p[2],p[3],p[4]);
//debug
p += nal_start;
//read_debug_nal_unit(h, p, nal_end - nal_start);
//export nalu data
char str[32];
sprintf(str,"./h264_nalu_frame/test%d.264",n);
FILE *fp = fopen(str, "a+b");
if(fp)
{
fwrite(p, nal_end - nal_start, 1, fp);
fclose(fp);
fp = NULL;
}
n++;
h264_nalu_cb(p, nal_end - nal_start);
//next frame
p += (nal_end - nal_start);
sz -= nal_end;
}
h264_free(h);
return 0;
}
int main(int argc, char *argv[])
{
uint8_t* buf = (uint8_t*)malloc( BUFSIZE );
FILE* infile = fopen("test0.264", "rb");
fread(buf,1,BUFSIZE,infile);
get_h264_nalu(buf, BUFSIZE);
fclose(infile);
free(buf);
return 0;
}
demo附件包下载
https://files.cnblogs.com/files/dong1/h264bitstream_demo.zip
5. hevcbitstream
hevc_analyze.c
/* * h264bitstream - a library for reading and writing H.264 video * Copyright (C) 2005-2007 Auroras Entertainment, LLC * * Written by Alex Izvorski <aizvorski@gmail.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "h264_stream.h" #include "hevc_stream.h" #include <stdlib.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <errno.h> #define BUFSIZE 32*1024*1024 #if (defined(__GNUC__)) #define HAVE_GETOPT_LONG #include <getopt.h> static struct option long_options[] = { { "probe", no_argument, NULL, 'p'}, { "output", required_argument, NULL, 'o'}, { "help", no_argument, NULL, 'h'}, { "verbose", required_argument, NULL, 'v'}, }; #endif static char options[] = "\t-o output_file, defaults to test.264\n" "\t-v verbose_level, print more info\n" "\t-p print codec for HTML5 video tag's codecs parameter, per RFC6381\n" "\t-h print this message and exit\n"; void usage( ) { fprintf( stderr, "h264_analyze, version 0.2.0\n"); fprintf( stderr, "Analyze H.264 bitstreams in Annex B format\n"); fprintf( stderr, "Usage: \n"); fprintf( stderr, "h264_analyze [options] <input bitstream>\noptions:\n%s\n", options); } int main(int argc, char *argv[]) { FILE* infile; uint8_t* buf = (uint8_t*)malloc( BUFSIZE ); hevc_stream_t* h = hevc_new(); if (argc < 2) { usage(); return EXIT_FAILURE; } int opt_verbose = 1; int opt_probe = 0; #ifdef HAVE_GETOPT_LONG int c; int long_options_index; extern char* optarg; extern int optind; while ( ( c = getopt_long( argc, argv, "o:phv:", long_options, &long_options_index) ) != -1 ) { switch ( c ) { case 'o': if (h264_dbgfile == NULL) { h264_dbgfile = fopen( optarg, "wt"); } break; case 'p': opt_probe = 1; opt_verbose = 0; break; case 'v': opt_verbose = atoi( optarg ); break; case 'h': default: usage( ); return 1; } } infile = fopen(argv[optind], "rb"); #else infile = fopen(argv[1], "rb"); #endif if (infile == NULL) { fprintf( stderr, "!! Error: could not open file: %s \n", strerror(errno)); exit(EXIT_FAILURE); } if (h264_dbgfile == NULL) { h264_dbgfile = stdout; } size_t rsz = 0; size_t sz = 0; int64_t off = 0; uint8_t* p = buf; int nal_start, nal_end; while (1) { rsz = fread(buf + sz, 1, BUFSIZE - sz, infile); if (rsz == 0) { if (ferror(infile)) { fprintf( stderr, "!! Error: read failed: %s \n", strerror(errno)); break; } break; // if (feof(infile)) } sz += rsz; while (find_nal_unit(p, sz, &nal_start, &nal_end) > 0) { if ( opt_verbose > 0 ) { fprintf( h264_dbgfile, "!! Found NAL at offset %lld (0x%04llX), size %lld (0x%04llX) \n", (long long int)(off + (p - buf) + nal_start), (long long int)(off + (p - buf) + nal_start), (long long int)(nal_end - nal_start), (long long int)(nal_end - nal_start) ); } p += nal_start; //read_debug_nal_unit(h, p, nal_end - nal_start); /* if ( opt_probe && h->nal->nal_unit_type == NAL_UNIT_TYPE_SPS ) { // print codec parameter, per RFC 6381. int constraint_byte = h->sps->constraint_set0_flag << 7; constraint_byte = h->sps->constraint_set1_flag << 6; constraint_byte = h->sps->constraint_set2_flag << 5; constraint_byte = h->sps->constraint_set3_flag << 4; constraint_byte = h->sps->constraint_set4_flag << 3; constraint_byte = h->sps->constraint_set4_flag << 3; fprintf( h264_dbgfile, "codec: avc1.%02X%02X%02X\n",h->sps->profile_idc, constraint_byte, h->sps->level_idc ); // TODO: add more, move to h264_stream (?) break; // we've seen enough, bailing out. } */ if ( opt_verbose > 0 ) { // fprintf( h264_dbgfile, "XX "); // debug_bytes(p-4, nal_end - nal_start + 4 >= 16 ? 16: nal_end - nal_start + 4); // debug_nal(h, h->nal); } p += (nal_end - nal_start); sz -= nal_end; } // if no NALs found in buffer, discard it if (p == buf) { fprintf( stderr, "!! Did not find any NALs between offset %lld (0x%04llX), size %lld (0x%04llX), discarding \n", (long long int)off, (long long int)off, (long long int)off + sz, (long long int)off + sz); p = buf + sz; sz = 0; } memmove(buf, p, sz); off += p - buf; p = buf; } hevc_free(h); free(buf); fclose(h264_dbgfile); fclose(infile); return 0; }
export LD_LIBRARY_PATH=$(pwd)/_install/lib:$LD_LIBRARY_PATH
gcc hevc_analyze.c -o hevc_analyze -I $(pwd)/_install/include/hevcbitstream -L $(pwd)/_install/lib -lhevcbitstream
./hevc_analyze jellyfish-3-mbps-hd-hevc.mkv
Media Samples
https://www.cnblogs.com/dong1/p/14040171.html
https://github.com/aizvorski/h264bitstream
https://github.com/leslie-wang/hevcbitstream