Giter VIP home page Giter VIP logo

h264bitstream's Introduction

A library to read and write H.264 video bitstreams, in particular to examine or modify headers.

CircleCI

Compile and Install with CMake

There are many variations of same CMake commands. You can run commands from the project root directory. You can create a build-directory and run commands from it. Read the official CMake documentation for more information.

All commands below should be run from the project root directory.

  1. Configure the project:
cmake -S . -B .builddir

Here you can specify the compiler (CMAKE_C_COMPILER), build type (CMAKE_BUILD_TYPE) and several other features, that do fine tuning of your building process.

Remember, that in case of gcc and clang you cannot build both debug and release binaries into one directory. You should use separate directories for every build configuration.
On the other hand, msvc supports multi-config building, as it creates subfolders for each config.

  1. Build the project:
cmake --build .builddir
  1. Optionally, install the binaries and headers into /usr/local:
cmake --install .builddir

CMake creates the file tree:

/usr/local:
├── bin
│   ├── h264_analyze
│   └── svc_split
├── include
│   ├── bs.h
│   ├── h264_avcc.h
│   ├── h264_sei.h
│   └── h264_stream.h
├── lib
│   └── libh264bitstream.a
└── share
    └── pkgconfig
        └── libh264bitstream.pc

Compile and Install with Autotools

  1. Install pre-requisites (Debian, Ubuntu)

    sudo apt-get install build-essential libtool autoconf ffmpeg
  2. Auto-reconfigure the project

    autoreconf -i
  3. Run the generated configure script and build the project

    ./configure --prefix=/usr/local
    make
  4. Optionally, install the binaries in /usr/local/

    make install

This will produce /usr/local/bin/h264_analyze and /usr/local/lib/libh264bitstream.

Example Code

Read one data unit (NAL, or network abstraction layer unit) out of an H264 bitstream and print it out:

int nal_start, nal_end;
uint8_t* buf;
int len;
// read some H264 data into buf
h264_stream_t* h = h264_new();
find_nal_unit(buf, len, &nal_start, &nal_end);
read_nal_unit(h, &buf[nal_start], nal_end - nal_start);
debug_nal(h,h->nal);

Goals

The main design goal is provide a complete, fully standards-compliant open-source library for reading and writing H264 streams.

Reading and writing headers (sequence and picture parameter sets, slice headers, etc) is a higher priority goal than reading and writing encoded picture data, and has been implemented first.

Secondary goals are portability and a simple, clean API. The library uses a subset of the language features of the C99 standard, without any compiler-specific extensions or dependence on a particular operating system or hardware.

This library is not an encoder or decoder, although you could use it to make writing an encoder or decoder much easier. It understands the syntax of H264, but not the semantics (meaning) of the data it reads or writes.

Implementation Status

Everything in the H264 standard is implemented except for:

  • parsing of diffeent SEI messages
  • SPS extension
  • slice data
  • slice data partitioning

Most of the unimplemented data will be correctly skipped when reading and ignored (not written) while writing; the code to read/write it is present as a stub, but they require somewhat more complex data structures to store the data, and those are not implemented yet.

Reading and writing slice data is complex and may not be fully implemented soon (target: 1.0.0 version), although there is some work-in-progress code for it.

Slice data partitioning will not be implemented in the forseeable future. It would require extensive changes to the library, and as it is only available in Extended Profile, its utility is limited.

Documentation

The library follows the H264 standard verbatim in most cases, including the naming of most variables and some functions.

A copy of the standard can be obtained from ITU (at http://www.itu.int/rec/T-REC-H.264/e ).

The public API documentation can be generated using Doxygen (run "make dox", the results are in the dox/ subdirectory).

The public API consists of:

    h264_new
    h264_free
    find_nal_unit
    read_nal_unit
    write_nal_unit
    rbsp_to_nal
    nal_to_rbsp
    debug_nal

plus direct access to the fields of h264_stream_t and the data structures nested in that.

Using other functions contained in the library to directly read or write specific types of NALs or parts thereof is not part of the public API, although it is not hard to do if you prepare the required bs_t argument. Please also note that using rbsp functions requires you also to perform handle RBSP to NAL (and vice versa) translation by calling rbsp_to_nal and nal_to_rbsp.

Programming Notes

All data types are stored in simple int fields in various structures, sometimes nested structures (which are guaranteed to be non-null if the containing structure is non-null, and may therefore be safely dereferenced). These fields can be used and assigned to directly; due to the very large number of fields, there are no accessor functions. Boolean values are 0 for false and 1 for true. Unsigned and signed integers can be assigned and read directly.

The currently active picture parameter set, sequence parameter set, slice header and nal are stored as fields in the h264_stream_t structure h which represents the stream being read.

For example, to write a simple SPS, use code like this:

    h264_stream_t* h = h264_new();

    h->nal->nal_ref_idc = 0x03;
    h->nal->nal_unit_type = NAL_UNIT_TYPE_SPS;

    h->sps->profile_idc = 0x42;
    h->sps->level_idc = 0x33;
    h->sps->log2_max_frame_num_minus4 = 0x05;
    h->sps->log2_max_pic_order_cnt_lsb_minus4 = 0x06;
    h->sps->num_ref_frames = 0x01;
    h->sps->pic_width_in_mbs_minus1 = 0x2c;
    h->sps->pic_height_in_map_units_minus1 = 0x1d;
    h->sps->frame_mbs_only_flag = 0x01;
    
    int len = write_nal_unit(h, buf, size);

All operations rely on an underlying set of bitstream functions which operate on bs_t* structures. Those are inherently buffer-overflow-safe and endiannes-independent, but provide only limited error handling at this time. Reads beyond the end of a buffer succeed and return an infinite sequence of zero bits; writes beyong the end of a buffer succeed and are ignored. To be sure that the buffer passed was large enough, check that the return of the read_nal_unit or write_nal_unit is less than the size of the buffer you passed in; if it is equal it is possible you're missing the end of the data.

You should always call find_nal_unit before calling read_nal_unit as shown in the quick start example. Successive reads without a find may fail, either due to bugs in the handling of the various types of rbsp padding, or because the stream is not compliant.

Limitations

The library does not try to maintain a table of different SPS and PPS, nor does it check that pic_parameter_set_id and seq_parameter_set_id in the current nal match those of the last read SPS/PPS. It stores the most recently seen SPS and PPS, and assumes those are applicable. If you are likely to encounter streams with multiple PPS or SPS, as a workaround you can store copies of each SPS/PPS which is read, check the corresponding id in other elements after reading, and if they do not match substitute the correct parameter set and re-read. This limitation will be removed in a later version.

Known Bugs

  • if attempting to write SLICE_TYPE_*_ALT slices, resulting slice header could be incorrect in versions <= 0.1.6

  • if no nal was found in entire processing buffer, h264_analyze could exit prematurely in versions <= 0.1.6

  • writing complete nals did not work correctly in versions <= 0.1.5

  • rbsp_trailing_bits could be (very rarely) handled incorrectly in versions <= 0.1.5

  • attempting to write decoded reference picture marking or reference picture list reordering data results in unpredictable behaviour

Copyright

Copyright (C) 2013-2017 Alex Izvorski and contributors
Copyright (C) 2008-2012 Alex Izvorski and Alex Giladi
Copyright (C) 2005-2007 Auroras Entertainment, LLC

Written by Alex Izvorski [email protected]

This library is distributed under the GNU Lesser General Public License.

Please see the file LICENSE for more details.

Homepage: https://github.com/aizvorski/h264bitstream/

h264bitstream's People

Contributors

aizvorski avatar antoneliasson avatar jetmeta avatar kradhub avatar leslie-wang avatar lostinkadath avatar mpromonet avatar mvasin avatar paintcan avatar sgadrat-anevia avatar tsvetomir avatar zenexer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

h264bitstream's Issues

How do I install & use h264bitstream?

Sorry if this is the wrong place. I searched and this is all I found.

h264bitstream is a library, right?
Can you recommend an application that uses it to display to me the headers and values of AVC (H.264) videos?
How do I install h264bitstream? My attempt follows:

mark@mark-VirtualBox:~$ sudo apt-get install build-essential libtool autoconf ffmpeg
[sudo] password for mark:
Reading package lists... Done
Building dependency tree
Reading state information... Done
autoconf is already the newest version (2.69-11.1).
libtool is already the newest version (2.4.6-14).
The following additional packages will be installed:
g++ g++-9 libavresample4 libstdc++-9-dev
Suggested packages:
ffmpeg-doc g++-multilib g++-9-multilib gcc-9-doc libstdc++-9-doc
The following NEW packages will be installed:
build-essential ffmpeg g++ g++-9 libavresample4 libstdc++-9-dev
0 upgraded, 6 newly installed, 0 to remove and 0 not upgraded.
Need to get 11.7 MB of archives.
After this operation, 49.1 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 https://mirrors.gigenet.com/ubuntuarchive focal-updates/main amd64 libstdc++-9-dev amd64 9.4.0-1ubuntu1~20.04.2 [1,722 kB]
Get:2 https://mirrors.gigenet.com/ubuntuarchive focal-updates/main amd64 g++-9 amd64 9.4.0-1ubuntu1~20.04.2 [8,421 kB]
Get:3 https://mirrors.gigenet.com/ubuntuarchive focal/main amd64 g++ amd64 4:9.3.0-1ubuntu2 [1,604 B]
Get:4 https://mirrors.gigenet.com/ubuntuarchive focal-updates/main amd64 build-essential amd64 12.8ubuntu1.1 [4,664 B]
Get:5 https://mirrors.gigenet.com/ubuntuarchive focal-updates/universe amd64 libavresample4 amd64 7:4.2.7-0ubuntu0.1 [54.2 kB]
Get:6 https://mirrors.gigenet.com/ubuntuarchive focal-updates/universe amd64 ffmpeg amd64 7:4.2.7-0ubuntu0.1 [1,453 kB]
Fetched 11.7 MB in 4s (3,322 kB/s)
Selecting previously unselected package libstdc++-9-dev:amd64.
(Reading database ... 404185 files and directories currently installed.)
Preparing to unpack .../0-libstdc++-9-dev_9.4.0-1ubuntu1~20.04.2_amd64.deb ...
Unpacking libstdc++-9-dev:amd64 (9.4.0-1ubuntu1~20.04.2) ...
Selecting previously unselected package g++-9.
Preparing to unpack .../1-g++-9_9.4.0-1ubuntu1~20.04.2_amd64.deb ...
Unpacking g++-9 (9.4.0-1ubuntu1~20.04.2) ...
Selecting previously unselected package g++.
Preparing to unpack .../2-g++_4%3a9.3.0-1ubuntu2_amd64.deb ...
Unpacking g++ (4:9.3.0-1ubuntu2) ...
Selecting previously unselected package build-essential.
Preparing to unpack .../3-build-essential_12.8ubuntu1.1_amd64.deb ...
Unpacking build-essential (12.8ubuntu1.1) ...
Selecting previously unselected package libavresample4:amd64.
Preparing to unpack .../4-libavresample4_7%3a4.2.7-0ubuntu0.1_amd64.deb ...
Unpacking libavresample4:amd64 (7:4.2.7-0ubuntu0.1) ...
Selecting previously unselected package ffmpeg.
Preparing to unpack .../5-ffmpeg_7%3a4.2.7-0ubuntu0.1_amd64.deb ...
Unpacking ffmpeg (7:4.2.7-0ubuntu0.1) ...
Setting up libstdc++-9-dev:amd64 (9.4.0-1ubuntu1~20.04.2) ...
Setting up libavresample4:amd64 (7:4.2.7-0ubuntu0.1) ...
Setting up g++-9 (9.4.0-1ubuntu1~20.04.2) ...
Setting up g++ (4:9.3.0-1ubuntu2) ...
update-alternatives: using /usr/bin/g++ to provide /usr/bin/c++ (c++) in auto mode
Setting up build-essential (12.8ubuntu1.1) ...
Setting up ffmpeg (7:4.2.7-0ubuntu0.1) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for libc-bin (2.31-0ubuntu9.12) ...
mark@mark-VirtualBox:~$ autoreconf -i
autoreconf: 'configure.ac' or 'configure.in' is required
mark@mark-VirtualBox:~$

[Error] - SPS that contains scaling lists

Hi @aizvorski

I try to read SPS with scaling list but I get error when I run the program.

Segmentation fault (core dumped)

I use live555 to get h264 stream

My camera send first

sprop-parameter-sets=Z2QAKK2ECSZuIzSQgSTNxGaSECSZuIzSQgSTNxGaSECSZuIzSQgSTNxGaSEFTS69fX5P6/J9eutVCCppdevr8n9fk+vXWqtAUBf8uAqkAAADAAQAAAMCWYEAD6AABGUb3vheEQjU,aO48sA==

I run base64Decode and the result I pass it through h264bitstream and I get the error.

With other SPS without scaling list work good.

Thank you so much.

segmentation fault in read_slice_layer_rbsp

Hello. I caught a segmentation fault while working with an H264 video. This happens after calling the methods
find_nal_unit(...) and read_nal_unit(...) with the next set of bytes in hex:
"00000001419a246c437ffea7840000030000097800000001"

Application crashes in class h264_stream.c of method read_slice_layer_rbsp(...). Variable slice_data->rbsp_size is equal to negative value when we perform memcpy(...).

shared library building fails

<command-line>:0:0: note: this is the location of the previous definition
depbase=`echo h264_nal_for_app.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
gcc -DPACKAGE_NAME=\"h264bitstream\" -DPACKAGE_TARNAME=\"h264bitstream\" -DPACKAGE_VERSION=\"0.2.0\" -DPACKAGE_STRING=\"h264bitstream\ 0.2.0\" -DPACKAGE_BUGREPORT=\"[email protected]\" -DPACKAGE_URL=\"\" -DPACKAGE=\"h264bitstream\" -DVERSION=\"0.2.0\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -DHAVE_GETOPT_LONG=1 -DNDEBUG=/\*\*/ -I.    -I. -Wall -std=c99 -std=c99 -Wno-error -g -O2 -MT h264_nal_for_app.o -MD -MP -MF $depbase.Tpo -c -o h264_nal_for_app.o h264_nal_for_app.c &&\
mv -f $depbase.Tpo $depbase.Po
/bin/sh ./libtool  --tag=CC   --mode=link gcc -I. -Wall -std=c99 -std=c99 -Wno-error -g -O2 -lm  -o h264_analyze h264_analyze.o h264_nal_for_app.o libh264bitstream.la 
libtool: link: gcc -I. -Wall -std=c99 -std=c99 -Wno-error -g -O2 -o .libs/h264_analyze h264_analyze.o h264_nal_for_app.o  -lm ./.libs/libh264bitstream.so
./.libs/libh264bitstream.so: undefined reference to `debug_sps'
./.libs/libh264bitstream.so: undefined reference to `debug_pps'
collect2: error: ld returned 1 exit status
Makefile:510: recipe for target 'h264_analyze' failed
make: *** [h264_analyze] Error 1
[ERR]
14:24:24krieger@zver /usr/local/src/h264bitstream
 $ grep debug_pps * -RnI
h264_avcc.c:140:    debug_pps(avcc->pps_table[i]);
h264_stream.h:147:   @see debug_pps
h264_stream.h:439:void debug_pps(pps_t* pps);
[OK]
14:24:36krieger@zver /usr/local/src/h264bitstream
 $ grep debug_sps * -RnI
h264_avcc.c:131:    debug_sps(avcc->sps_table[i]);
h264_stream.h:42:   @see debug_sps
h264_stream.h:438:void debug_sps(sps_t* sps);

Extract motion vectors

Hi there,

I'm looking for a very fast way to extract motion vectors from an h264 stream inside some container. I just need the x,y coordinates of the block and it's dx,dy movement. I'd like to cut out any CPU time not contributing to the motion vectors. The data is coming from ffmpeg (encoding as h264 in hardware) so I can set the container format to anything.

Is this repo what I'm after?

Please excuse my ignorance of h264 but I can't answer this question by looking at the code, nor would I know how to do it if you just said "yes", so some guidance would be very much appreciated.

I know this isn't really an "issue" but github seem to have disabled all other forms of messaging.

TIA, Adrian.

Write a h264 stream copy-paste using this library

Hello,

I'd need to write a small tool that reads an h264 file, reads the NALs, modifies current data and eventually adds new units (more specifically, SEI data). I would like to start from a simple tool that copy-pastes an h264 bitstream from one file to another, with the output one being readable by players like mpv or derived tools like https://mradionov.github.io/h264-bitstream-viewer/.

This is what's being reported in the README:

'Reading and writing slice data is complex and may not be fully implemented soon (target: 1.0.0 version), although there is some work-in-progress code for it.'

Does this mean that it's possible to use this library to manipulate actual h264 data, obtaining playable results? If not, could you please guide me through the steps that would be needed to realize such a copy-paste tool? I have not been able to find any suitable example, although it should be one of the simplest usages of this library. Thanks in advance!

more_rbsp_data function is wrong

I am using the h264bitstream command to help me writing an h.264 decoder and i think the implementation of function more_rbsp_data() in h264bitstream_data is wrong. The parser is not detecting PPS with transform_8x8_mode_flag = 1 (nor the remaining PPS syntax elements) due to more_rbsp_data() interpreting that bit as the rsbp_stop_bit. Also, sei messages are not correctly parsed. This is a working implementation:

int more_rbsp_data(h264_stream_t* h, bs_t* bs) {

  /* no more data */
  if (bs_eof(bs)) return 0;

  /* no rbsp_stop_bit yet */
  if (bs_peek_u1(bs) == 0) return 1;

  /* next bit is 1, is it the rsbp_stop_bit? only if the rest of bits are 0 */
  bs_t aux;
  bs_clone(&aux, bs);
  bs_skip_u1(&aux);
  while(!bs_eof(&aux)) {
    /* A later bit was 1, it wasn't the rsbp_stop_bit */
    if (bs_read_u1(&aux) == 1) return 1;
  }

  /* All following bits were 0, it was the rsbp_stop_bit */
  return 0;

}

Problem with installed headers

With the latest master, when I run make install, the headers are placed in the root include directory (for example, /usr/include/ ). Also, bs.h is not installed, even though both the h264bitstream headers themselves and programs using h264bitstream need it.

So I suggest to install the headers in a h264bitstream/ subdirectory instead, and also install bs.h. Installing them in a subdirectory keeps the root include directory cleaner, and also prevents name collisions ("bs.h" sounds fairly generic).

Compile command for h264bitstream

Hi,
I'm getting the following error while compiling the h264_analyze.c code:
h264_analyze.c:(.text+0xb1): undefined reference to h264_new' h264_analyze.c:(.text+0xf8): undefined reference to h264_dbgfile'
h264_analyze.c:(.text+0x118): undefined reference to h264_dbgfile' h264_analyze.c:(.text+0x1eb): undefined reference to h264_dbgfile'
h264_analyze.c:(.text+0x1fe): undefined reference to h264_dbgfile' h264_analyze.c:(.text+0x2fe): undefined reference to h264_dbgfile'
h264_analyze.c:(.text+0x33a): undefined reference to read_debug_nal_unit' h264_analyze.c:(.text+0x3d9): undefined reference to h264_dbgfile'
h264_analyze.c:(.text+0x426): undefined reference to find_nal_unit' h264_analyze.c:(.text+0x4d1): undefined reference to h264_free'
h264_analyze.c:(.text+0x4e4): undefined reference to `h264_dbgfile'
Can i get the right compile command with flags?

SVC support

Thanks for the wonderful work. I'm wondering if you have any plan to support SVC. If no, I'd like to contribute to it. Please let me know your thought.

Exponential golomb encoding fixes

I don't know if it will be helpful, but I made a bunch of changes to this library to fix some problems that I was seeing in my h264 stream. In particular, there were instances where some SPS/PPS golomb encoded values were not encoding correctly due to missing support for "big" values. H264 allows for values in some fields which are larger than what your bs_write_ue method allowed. The folks that work on the x264 library had to fix this some time back as well, so I formulated my solution based on their golomb encode/decode source. See the "big" variant that I added.

There are other various changes added as well, though mostly for my own purposes, so they may not be useful (or may be wrong in accordance with your intentions). Just thought I'd throw my work up here in case it was useful to anyone else:

https://gitlab.com/openrov/h264bitstream/tree/openrov

write_nal_unit() function prints spare null byte at buf[0]

 $ cat ./build.sh 
#!/bin/bash                                                                                                                                                                                   

gcc -I /usr/local/src/h264bitstream/   gen_stream.c   /usr/local/src/h264bitstream/.libs/libh264bitstream.a   -o gen_stream
[OK]
15:49:26krieger@zver ~/work/employers/bluecherry/h264_stream_gen
 $ ./build.sh 
[OK]
15:49:27krieger@zver ~/work/employers/bluecherry/h264_stream_gen
 $ ./gen_stream 
Stream start headers:
00 00 00 01 00 67 42 00 1e 92 44 05 a0 92 20 00 00 00 01 00 68 ce 08 48 80 
Header before keyframe:
00 00 00 01 00 25 b8 04 00 
Header before non-key frame 1:
00 00 00 01 00 21 e0 41 
Header before non-key frame 2:
00 00 00 01 00 21 e0 82 
Header before non-key frame 3:
00 00 00 01 00 21 e0 c3 
[OK]
#include <h264_stream.h>

#define MIN(x, y) ({                            \
        typeof(x) _min1 = (x);                  \
        typeof(y) _min2 = (y);                  \
        (void) (&_min1 == &_min2);              \
        _min1 < _min2 ? _min1 : _min2; })

h264_stream_t* h = NULL;
uint8_t marker[] = {0x00, 0x00, 0x00, 0x01};

ssize_t write_stream_start(uint8_t *buf, size_t size)
{
        ssize_t off = 0;


        /* SPS */
        if (size - off - 4 < 0)
                return off;  // TODO indicate error and not just "normal" premature return
        memcpy(buf + off, marker, MIN(sizeof(marker), size - off));
        off += 4;

        h->nal->nal_ref_idc = 0x03;
        h->nal->nal_unit_type = NAL_UNIT_TYPE_SPS;

        h->sps->profile_idc = 0x42;  /* == 66, baseline */
        h->sps->level_idc = 30;
        h->sps->log2_max_frame_num_minus4 = 3;
        h->sps->log2_max_pic_order_cnt_lsb_minus4 = 3;
        h->sps->num_ref_frames = 0x01;
        h->sps->pic_width_in_mbs_minus1 = 0x2c;  /* == 44 */
        h->sps->pic_height_in_map_units_minus1 = 35; // 0x1d;
        h->sps->frame_mbs_only_flag = 0x01;

        off += write_nal_unit(h, buf + off, size - off);


        /* PPS */
        if (size - off - 4 < 0)
                return off;  // TODO indicate error and not just "normal" premature return
        memcpy(buf + off, marker, MIN(sizeof(marker), size - off));
        off += 4;

        h->nal->nal_ref_idc = 0x03;
        h->nal->nal_unit_type = NAL_UNIT_TYPE_PPS;

        h->pps->pic_parameter_set_id = 0;
        h->pps->seq_parameter_set_id = 0;
        h->pps->entropy_coding_mode_flag = 0;
        h->pps->pic_order_present_flag = 0;
        h->pps->num_slice_groups_minus1 = 0;
        h->pps->num_ref_idx_l0_active_minus1 = 0;
        h->pps->num_ref_idx_l1_active_minus1 = 0;
        h->pps->weighted_pred_flag = 0;
        h->pps->weighted_bipred_idc = 0;
        h->pps->pic_init_qp_minus26 = 2;
        h->pps->pic_init_qs_minus26 = 2;
        h->pps->chroma_qp_index_offset = 0;
        h->pps->deblocking_filter_control_present_flag = 0;
        h->pps->constrained_intra_pred_flag = 0;
        h->pps->redundant_pic_cnt_present_flag = 0;

        off += write_nal_unit(h, buf + off, size - off);

        return off;
}

ssize_t write_stream_middle_idr(uint8_t *buf, size_t size)
{
        ssize_t off = 0;

        if (size - off - 4 < 0)
                return off;  // TODO indicate error and not just "normal" premature return
        memcpy(buf + off, marker, MIN(sizeof(marker), size - off));
        off += 4;

        h->nal->nal_ref_idc = 1;
        h->nal->nal_unit_type = NAL_UNIT_TYPE_CODED_SLICE_IDR;
        h->sh->first_mb_in_slice = 0;
        h->sh->slice_type = 2;
        h->sh->pic_parameter_set_id = 0;
        h->sh->frame_num = 0;
        h->sh->idr_pic_id = 1;
        h->sh->pic_order_cnt_lsb = 0;
        h->sh->drpm.no_output_of_prior_pics_flag = 0;
        h->sh->drpm.long_term_reference_flag = 0;
        h->sh->slice_qp_delta = 0;

        off += write_nal_unit(h, buf + off, size - off);

        return off;
}

ssize_t write_stream_middle_non_idr(uint8_t *buf, size_t size, int frame_num_in_gop)
{
        ssize_t off = 0;

        if (size - off - 4 < 0)
                return off;  // TODO indicate error and not just "normal" premature return
        memcpy(buf + off, marker, MIN(sizeof(marker), size - off));
        off += 4;

        h->nal->nal_ref_idc = 1;
        h->nal->nal_unit_type = NAL_UNIT_TYPE_CODED_SLICE_NON_IDR;
        h->sh->first_mb_in_slice = 0;
        h->sh->slice_type = SH_SLICE_TYPE_P;
        h->sh->pic_parameter_set_id = 0;
        h->sh->frame_num = frame_num_in_gop;
        h->sh->idr_pic_id = 1;
        h->sh->pic_order_cnt_lsb = frame_num_in_gop * 2;  /* for interlaced */
        h->sh->drpm.no_output_of_prior_pics_flag = 0;
        h->sh->drpm.long_term_reference_flag = 0;
        h->sh->slice_qp_delta = 0;

        off += write_nal_unit(h, buf + off, size - off);

        return off;
}

void print_buf(uint8_t *buf, ssize_t size)
{
        ssize_t i;
        for (i = 0; i < size; i++) {
                printf("%02x ", buf[i]);
        }
        printf("\n");
}

int main(int argc, uint8_t *argv[])
{
        ssize_t stream_start_len = 0;
        ssize_t stream_middle_len = 0;
        uint8_t stream_start[64] = { 0, };
        uint8_t stream_middle[64] = { 0, };
        int i;

        h = h264_new();

        printf("Stream start headers:\n");
        stream_start_len = write_stream_start(stream_start, sizeof(stream_start));
        print_buf(stream_start, stream_start_len);

        printf("Header before keyframe:\n");
        stream_middle_len = write_stream_middle_idr(stream_middle, sizeof(stream_middle));
        print_buf(stream_middle, stream_middle_len);

        for (i = 1; i < 4; i++) {
                printf("Header before non-key frame %d:\n", i);
                stream_middle_len = write_stream_middle_non_idr(stream_middle, sizeof(stream_middle), i);
                print_buf(stream_middle, stream_middle_len);
        }

        return 0;
}

rbsp_alignment_zero_bit should equal to zero

based on 7.4.2.11 RBSP trailing bits semantics
rbsp_stop_one_bit shall be equal to 1.
rbsp_alignment_zero_bit shall be equal to 0.

Code at h264_stream.in.c set it to 1.

//7.3.2.11 RBSP trailing bits syntax
void structure(rbsp_trailing_bits)(h264_stream_t* h, bs_t* b)
{
    value( rbsp_stop_one_bit, f(1, 1) );

    while( !bs_byte_aligned(b) )
    {
        value( rbsp_alignment_zero_bit, f(1, 0) );
    }
}

"error while loading shared libraries" when running h264_analyze

I installed the tool on Ubuntu 16.04 as per the instructions. When I try to run it, I get:

h264_analyze: error while loading shared libraries: libh264bitstream.so.0: cannot open shared object file: No such file or directory

I do have the libraries in /usr/local/lib:

ll /usr/local/lib/libh*
-rw-r--r-- 1 root root 1418348 Jul 17 10:58 /usr/local/lib/libh264bitstream.a
-rwxr-xr-x 1 root root     996 Jul 17 10:58 /usr/local/lib/libh264bitstream.la
lrwxrwxrwx 1 root root      25 Jul 17 10:58 /usr/local/lib/libh264bitstream.so -> libh264bitstream.so.0.0.0
lrwxrwxrwx 1 root root      25 Jul 17 10:58 /usr/local/lib/libh264bitstream.so.0 -> libh264bitstream.so.0.0.0
-rwxr-xr-x 1 root root  906512 Jul 17 10:58 /usr/local/lib/libh264bitstream.so.0.0.0

And they are in the library path:

cat /etc/ld.so.conf.d/libc.conf
# libc default configuration
/usr/local/lib

The output from sudo make install:

make[1]: Entering directory '/home/werner/Documents/Projects/h264bitstream'
 /bin/mkdir -p '/usr/local/lib'
 /bin/bash ./libtool   --mode=install /usr/bin/install -c   libh264bitstream.la '/usr/local/lib'
libtool: install: /usr/bin/install -c .libs/libh264bitstream.so.0.0.0 /usr/local/lib/libh264bitstream.so.0.0.0
libtool: install: (cd /usr/local/lib && { ln -s -f libh264bitstream.so.0.0.0 libh264bitstream.so.0 || { rm -f libh264bitstream.so.0 && ln -s libh264bitstream.so.0.0.0 libh264bitstream.so.0; }; })
libtool: install: (cd /usr/local/lib && { ln -s -f libh264bitstream.so.0.0.0 libh264bitstream.so || { rm -f libh264bitstream.so && ln -s libh264bitstream.so.0.0.0 libh264bitstream.so; }; })
libtool: install: /usr/bin/install -c .libs/libh264bitstream.lai /usr/local/lib/libh264bitstream.la
libtool: install: /usr/bin/install -c .libs/libh264bitstream.a /usr/local/lib/libh264bitstream.a
libtool: install: chmod 644 /usr/local/lib/libh264bitstream.a
libtool: install: ranlib /usr/local/lib/libh264bitstream.a
libtool: finish: PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/sbin" ldconfig -n /usr/local/lib
----------------------------------------------------------------------
Libraries have been installed in:
   /usr/local/lib

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the '-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the 'LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the 'LD_RUN_PATH' environment variable
     during linking
   - use the '-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to '/etc/ld.so.conf'


See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------
 /bin/mkdir -p '/usr/local/bin'
  /bin/bash ./libtool   --mode=install /usr/bin/install -c h264_analyze svc_split '/usr/local/bin'
libtool: install: /usr/bin/install -c .libs/h264_analyze /usr/local/bin/h264_analyze
libtool: install: /usr/bin/install -c .libs/svc_split /usr/local/bin/svc_split
 /bin/mkdir -p '/usr/local/include'
 /usr/bin/install -c -m 644 h264_stream.h h264_sei.h h264_avcc.h '/usr/local/include'
 /bin/mkdir -p '/usr/local/lib/pkgconfig'
 /usr/bin/install -c -m 644 libh264bitstream.pc '/usr/local/lib/pkgconfig'
 /bin/mkdir -p '/usr/local/include/h264bitstream'
 /usr/bin/install -c -m 644 h264_stream.h h264_sei.h h264_avcc.h bs.h '/usr/local/include/h264bitstream'
make[1]: Leaving directory '/home/werner/Documents/Projects/h264bitstream'

When I first tried make install without sudo, I got:

make[1]: Entering directory '/home/werner/Documents/Projects/h264bitstream'
 /bin/mkdir -p '/usr/local/lib'
 /bin/bash ./libtool   --mode=install /usr/bin/install -c   libh264bitstream.la '/usr/local/lib'
libtool: install: /usr/bin/install -c .libs/libh264bitstream.so.0.0.0 /usr/local/lib/libh264bitstream.so.0.0.0
/usr/bin/install: cannot create regular file '/usr/local/lib/libh264bitstream.so.0.0.0': Permission denied
Makefile:433: recipe for target 'install-libLTLIBRARIES' failed
make[1]: *** [install-libLTLIBRARIES] Error 1
make[1]: Leaving directory '/home/werner/Documents/Projects/h264bitstream'
Makefile:872: recipe for target 'install-am' failed
make: *** [install-am] Error 2

Any idea as to what could be wrong?

sps_table support is broken, complete failure when seq_parameter_set_id != 0

The memcpy at the end of read_seq_parameter_set_rbsp() overwrites the struct it just filled with
a copy of what's in sps_table. Since h->sps == h->sps_table[0] it just filled that one, the memcpy in the id=0 case is (un?)luckily a no-op, while in all other cases the values just read are just all cleared to 0.

Swapping src/dst can't work properly as is either, since h->sps == h->sps_table[0]: when we notice that seq_parameter_set_id != 0 we have already overwritten h->sps_table[0].

if(0)-ing this memcpy as a workaround works much better...

libh264bitstream.so.0 file not found

Here's my installation sequence:

docker run -ti $PWD:/workdir ubuntu
apt update
apt-get install build-essential libtool autoreconf git
git clone https://github.com/aizvorski/h264bitstream && cd h264bitstream
autoreconf -i
./configure --prefix=/usr/local
make
make install

Then I run h264_analyze and get

root@b64adfd865e3:/h264bitstream# h264_analyze
h264_analyze: error while loading shared libraries: libh264bitstream.so.0: cannot open shared object file: No such file or directory

platform support

could we compile by mingw for ms windows? if not,could we support cmake?

in addition,compile on centos 6.7 with gcc 4.4.7(which have not full support for c99)will result in some error,that's this version of gcc doesn't supoort anonymous union,below is part of compile error:
h264_stream.h:199: warning: declaration does not declare anything
h264_stream.c: In function ‘read_subset_seq_parameter_set_rbsp’:
h264_stream.c:504: error: ‘sps_subset_t’ has no member named ‘sps_svc_ext’
h264_stream.c: In function ‘read_seq_parameter_set_svc_extension’:
h264_stream.c:529: error: ‘sps_subset_t’ has no member named ‘sps_svc_ext’
h264_stream.c: In function ‘read_pic_parameter_set_rbsp’:
h264_stream.c:771: warning: suggest parentheses around comparison in operand of ‘|’
h264_stream.c: In function ‘read_slice_header_in_scalable_extension’:
h264_stream.c:1334: error: ‘sps_subset_t’ has no member named ‘sps_svc_ext’
h264_stream.c:1371: error: ‘sps_subset_t’ has no member named ‘sps_svc_ext’
we can fix this issue by modify configure.ac
modify EXTRA_CFLAGS='-std=c99 -Wno-error' to EXTRA_CFLAGS='-std=gnu99 -Wno-error'

reading and writing slice data

h264_slice_data.c file provides some functions for extracting slice and macroblock information but it is not implemented in h264_analyze. Is there going to be a patch for this anytime soon? Would it be straightforward to modify slice data functions or is there still a lot of work to do? It is regarded as a "large project" in the readme file, that's why I'm asking.

debug_nal not existent?

I cannot find the definition of debug_nal. Is something wrong with my editor seacher of there simply isn't one anymore?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.