Packages
membrane_h264_ffmpeg_plugin
0.7.0
0.32.7
0.32.6
0.32.5
0.32.4
0.32.3
0.32.2
0.32.1
0.32.0
0.31.8
0.31.7
0.31.6
0.31.5
0.31.4
0.31.3
0.31.2
0.31.1
0.31.0
0.30.1
0.30.0
0.29.0
0.28.2
0.28.1
0.28.0
0.27.0
0.26.2
0.26.1
0.26.0
0.25.4
0.25.3
0.25.2
0.25.1
0.25.0
0.24.0
0.23.0
0.22.1
0.22.0
0.21.6
0.21.5
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.3
0.16.2
0.16.1
0.16.0
0.15.0
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.2
0.12.1
0.12.0
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.0
0.5.0
Membrane H264 decoder and encoder based on FFmpeg and x264
Current section
Files
Jump to
Current section
Files
c_src/membrane_h264_ffmpeg_plugin/parser.c
#include "parser.h"
void handle_destroy_state(UnifexEnv *env, State *state) {
UNIFEX_UNUSED(env);
if (state->parser_ctx != NULL) {
av_parser_close(state->parser_ctx);
}
if (state->codec_ctx != NULL) {
avcodec_free_context(&state->codec_ctx);
}
}
UNIFEX_TERM create(UnifexEnv *env) {
UNIFEX_TERM res;
State *state = unifex_alloc_state(env);
state->codec_ctx = NULL;
state->parser_ctx = NULL;
AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!codec) {
res = create_result_error(env, "nocodec");
goto exit_create;
}
state->parser_ctx = av_parser_init(codec->id);
if (!state->parser_ctx) {
res = create_result_error(env, "noparser");
goto exit_create;
}
state->codec_ctx = avcodec_alloc_context3(codec);
if (!state->codec_ctx) {
res = create_result_error(env, "codec_alloc");
goto exit_create;
}
if (avcodec_open2(state->codec_ctx, codec, NULL) < 0) {
res = create_result_error(env, "codec_open");
goto exit_create;
}
res = create_result_ok(env, state);
exit_create:
unifex_release_state(env, state);
return res;
}
UNIFEX_TERM parse(UnifexEnv *env, UnifexPayload *payload, State *state) {
UNIFEX_TERM res_term;
int ret;
size_t max_frames = 32, frames_cnt = 0;
unsigned *out_frame_sizes = unifex_alloc(max_frames * sizeof(unsigned));
AVPacket *pkt = NULL;
size_t old_size = payload->size;
ret =
unifex_payload_realloc(payload, old_size + AV_INPUT_BUFFER_PADDING_SIZE);
if (!ret) {
res_term = parse_result_error(env, "realloc");
goto exit_parse_frames;
}
memset(payload->data + old_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
pkt = av_packet_alloc();
av_init_packet(pkt);
uint8_t *data_ptr = payload->data;
size_t data_left = old_size;
while (data_left > 0) {
ret = av_parser_parse2(state->parser_ctx, state->codec_ctx, &pkt->data,
&pkt->size, data_ptr, data_left, AV_NOPTS_VALUE,
AV_NOPTS_VALUE, 0);
if (ret < 0) {
res_term = parse_result_error(env, "parsing");
goto exit_parse_frames;
}
data_ptr += ret;
data_left -= ret;
if (pkt->size > 0) {
if (frames_cnt >= max_frames) {
max_frames *= 2;
out_frame_sizes =
unifex_realloc(out_frame_sizes, max_frames * sizeof(unsigned));
}
out_frame_sizes[frames_cnt] = pkt->size;
frames_cnt++;
}
}
res_term = parse_result_ok(env, out_frame_sizes, frames_cnt);
exit_parse_frames:
unifex_free(out_frame_sizes);
av_packet_free(&pkt);
unifex_payload_realloc(payload, old_size);
return res_term;
}
UNIFEX_TERM get_parsed_meta(UnifexEnv *env, State *state) {
char *profile_atom;
switch (state->codec_ctx->profile) {
case FF_PROFILE_H264_CONSTRAINED_BASELINE:
profile_atom = "constrained_baseline";
break;
case FF_PROFILE_H264_BASELINE:
profile_atom = "baseline";
break;
case FF_PROFILE_H264_MAIN:
profile_atom = "main";
break;
case FF_PROFILE_H264_HIGH:
profile_atom = "high";
break;
case FF_PROFILE_H264_HIGH_10:
profile_atom = "high_10";
break;
case FF_PROFILE_H264_HIGH_422:
profile_atom = "high_422";
break;
case FF_PROFILE_H264_HIGH_444:
profile_atom = "high_444";
break;
case FF_PROFILE_H264_HIGH_10_INTRA:
profile_atom = "high_10_intra";
break;
case FF_PROFILE_H264_HIGH_422_INTRA:
profile_atom = "high_422_intra";
break;
case FF_PROFILE_H264_HIGH_444_INTRA:
profile_atom = "high_444_intra";
break;
default:
profile_atom = "unknown";
}
return get_parsed_meta_result_ok(env, state->parser_ctx->width,
state->parser_ctx->height, profile_atom);
}
UNIFEX_TERM flush(UnifexEnv *env, State *state) {
int ret;
uint8_t *data_ptr;
unsigned out_frame_size;
ret = av_parser_parse2(state->parser_ctx, state->codec_ctx, &data_ptr,
(int *)&out_frame_size, NULL, 0, AV_NOPTS_VALUE,
AV_NOPTS_VALUE, 0);
if (ret < 0) {
return parse_result_error(env, "parsing");
}
if (out_frame_size == 0) {
return flush_result_ok(env, NULL, 0);
}
return flush_result_ok(env, &out_frame_size, 1);
}