Packages
Membrane Multimedia Framework (FDK-AAC Element)
Current section
5 Versions
Jump to
Current section
5 Versions
Compare versions
6
files changed
+107
additions
-103
deletions
| @@ -41,6 +41,6 @@ brew install fdk-aac | |
| 41 41 | |
| 42 42 | Copyright 2018, [Software Mansion](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane) |
| 43 43 | |
| 44 | - [](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane) |
| 44 | + [](https://swmansion.com/?utm_source=git&utm_medium=readme&utm_campaign=membrane) |
| 45 45 | |
| 46 46 | Licensed under the [Apache License, Version 2.0](LICENSE) |
| @@ -2,7 +2,8 @@ | |
| 2 2 | |
| 3 3 | /** |
| 4 4 | * AAC Decoder implementation. |
| 5 | - * Heavily inspired by https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libfdk-aacdec.c |
| 5 | + * Heavily inspired by |
| 6 | + * https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libfdk-aacdec.c |
| 6 7 | */ |
| 7 8 | |
| 8 9 | #define DECODER_MAX_CHANNELS 8 |
| @@ -10,11 +11,12 @@ | |
| 10 11 | |
| 11 12 | /** |
| 12 13 | * Initializes AAC Decoder and returns State resource. |
| 13 | - * |
| 14 | + * |
| 14 15 | * On success, returns {:ok, decoder_state} |
| 15 16 | * In case of error, returns: |
| 16 17 | * - {:error, :unknown} - If AAC decoder cannot be initialized |
| 17 | - * - {:error, :no_memory} - If there's not enough memory to initialize AAC buffer |
| 18 | + * - {:error, :no_memory} - If there's not enough memory to initialize AAC |
| 19 | + * buffer |
| 18 20 | */ |
| 19 21 | UNIFEX_TERM create(UnifexEnv *env) { |
| 20 22 | State *state = unifex_alloc_state(env); |
| @@ -40,9 +42,9 @@ UNIFEX_TERM create(UnifexEnv *env) { | |
| 40 42 | |
| 41 43 | /** |
| 42 44 | * Returns AAC stream metadata |
| 43 | - * |
| 45 | + * |
| 44 46 | * Expects Native resource as argument |
| 45 | - * |
| 47 | + * |
| 46 48 | * Returns: |
| 47 49 | * - {:ok, {frame_size, sample_rate, channels}} |
| 48 50 | */ |
| @@ -51,22 +53,19 @@ UNIFEX_TERM get_metadata(UnifexEnv *env, State *state) { | |
| 51 53 | |
| 52 54 | CStreamInfo *stream_info = aacDecoder_GetStreamInfo(state->handle); |
| 53 55 | |
| 54 | - res = get_metadata_result( |
| 55 | - env, |
| 56 | - stream_info->frameSize, |
| 57 | - stream_info->sampleRate, |
| 58 | - stream_info->numChannels); |
| 56 | + res = get_metadata_result(env, stream_info->frameSize, |
| 57 | + stream_info->sampleRate, stream_info->numChannels); |
| 59 58 | return res; |
| 60 59 | } |
| 61 60 | |
| 62 61 | /** |
| 63 62 | * Fills internal AAC Decoder buffer with input buffer |
| 64 | - * |
| 63 | + * |
| 65 64 | * Expects: |
| 66 65 | * - Buffer to decode |
| 67 66 | * - Native resource |
| 68 67 | * as arguments |
| 69 | - * |
| 68 | + * |
| 70 69 | * Returns one of: |
| 71 70 | * - {:ok} |
| 72 71 | * - {:error, :invalid_data} |
| @@ -76,18 +75,17 @@ UNIFEX_TERM fill(UnifexEnv *env, UnifexPayload *in_payload, State *state) { | |
| 76 75 | AAC_DECODER_ERROR err; |
| 77 76 | UINT valid = in_payload->size; |
| 78 77 | |
| 79 | - err = aacDecoder_Fill( |
| 80 | - state->handle, |
| 81 | - &in_payload->data, |
| 82 | - &in_payload->size, |
| 83 | - &valid); |
| 78 | + err = aacDecoder_Fill(state->handle, &in_payload->data, &in_payload->size, |
| 79 | + &valid); |
| 84 80 | if (err != AAC_DEC_OK) { |
| 85 81 | MEMBRANE_WARN(env, "AAC: aacDecoder_Fill() failed: %x\n", err); |
| 86 82 | return fill_result_error_invalid_data(env); |
| 87 83 | } |
| 88 84 | if (valid != 0) { |
| 89 | - //See: https://github.com/mstorsjo/fdk-aac/blob/95858d7bd36f19bde4a9595e2bd68f195215b164/libAACdec/include/aacdecoder_lib.h#L1014 |
| 90 | - MEMBRANE_WARN(env, "AAC: aacDecoder_Fill() left %d bytes in input buffer\n", valid); |
| 85 | + // See: |
| 86 | + // https://github.com/mstorsjo/fdk-aac/blob/95858d7bd36f19bde4a9595e2bd68f195215b164/libAACdec/include/aacdecoder_lib.h#L1014 |
| 87 | + MEMBRANE_WARN(env, "AAC: aacDecoder_Fill() left %d bytes in input buffer\n", |
| 88 | + valid); |
| 91 89 | } |
| 92 90 | |
| 93 91 | res = fill_result_ok(env); |
| @@ -96,12 +94,12 @@ UNIFEX_TERM fill(UnifexEnv *env, UnifexPayload *in_payload, State *state) { | |
| 96 94 | |
| 97 95 | /** |
| 98 96 | * Decodes one input frame. |
| 99 | - * |
| 97 | + * |
| 100 98 | * Expects: |
| 101 99 | * - Buffer to decode |
| 102 100 | * - Native resource |
| 103 101 | * as arguments |
| 104 | - * |
| 102 | + * |
| 105 103 | * Returns one of: |
| 106 104 | * - {:ok, {decoded_frame, frame_size, sample_rate, channels}} |
| 107 105 | * decoded audio frame with stream info |
| @@ -109,17 +107,16 @@ UNIFEX_TERM fill(UnifexEnv *env, UnifexPayload *in_payload, State *state) { | |
| 109 107 | * - {:error, :not_enough_bits} |
| 110 108 | * - {:error, :unknown} |
| 111 109 | */ |
| 112 | - UNIFEX_TERM decode_frame(UnifexEnv *env, UnifexPayload *in_payload, State *state) { |
| 110 | + UNIFEX_TERM decode_frame(UnifexEnv *env, UnifexPayload *in_payload, |
| 111 | + State *state) { |
| 113 112 | UNIFEX_TERM res; |
| 114 113 | AAC_DECODER_ERROR err; |
| 115 114 | |
| 116 | - err = aacDecoder_DecodeFrame( |
| 117 | - state->handle, |
| 118 | - (INT_PCM *)state->decoder_buffer, |
| 119 | - state->decoder_buffer_size / sizeof(INT_PCM), |
| 120 | - 0); |
| 115 | + err = aacDecoder_DecodeFrame(state->handle, (INT_PCM *)state->decoder_buffer, |
| 116 | + state->decoder_buffer_size / sizeof(INT_PCM), 0); |
| 121 117 | if (err == AAC_DEC_NOT_ENOUGH_BITS) { |
| 122 | - MEMBRANE_WARN(env, "AAC: aacDecoder_DecodeFrame() - not enough bits supplied"); |
| 118 | + MEMBRANE_WARN(env, |
| 119 | + "AAC: aacDecoder_DecodeFrame() - not enough bits supplied"); |
| 123 120 | return decode_frame_result_error_not_enough_bits(env); |
| 124 121 | } |
| 125 122 | if (err != AAC_DEC_OK) { |
| @@ -129,16 +126,13 @@ UNIFEX_TERM decode_frame(UnifexEnv *env, UnifexPayload *in_payload, State *state | |
| 129 126 | |
| 130 127 | CStreamInfo *stream_info = aacDecoder_GetStreamInfo(state->handle); |
| 131 128 | |
| 132 | - UINT out_payload_size = stream_info->frameSize * stream_info->numChannels * sizeof(INT_PCM); |
| 133 | - UnifexPayload *out_payload = unifex_payload_alloc(env, in_payload->type, out_payload_size); |
| 134 | - memcpy( |
| 135 | - out_payload->data, |
| 136 | - state->decoder_buffer, |
| 137 | - out_payload_size); |
| 129 | + UINT out_payload_size = |
| 130 | + stream_info->frameSize * stream_info->numChannels * sizeof(INT_PCM); |
| 131 | + UnifexPayload *out_payload = |
| 132 | + unifex_payload_alloc(env, in_payload->type, out_payload_size); |
| 133 | + memcpy(out_payload->data, state->decoder_buffer, out_payload_size); |
| 138 134 | |
| 139 | - res = decode_frame_result_ok( |
| 140 | - env, |
| 141 | - out_payload); |
| 135 | + res = decode_frame_result_ok(env, out_payload); |
| 142 136 | unifex_payload_release_ptr(&out_payload); |
| 143 137 | return res; |
| 144 138 | } |
| @@ -3,14 +3,13 @@ | |
| 3 3 | #include <fdk-aac/aacdecoder_lib.h> |
| 4 4 | #include <membrane/membrane.h> |
| 5 5 | #define MEMBRANE_LOG_TAG "Membrane.Element.FDK.AAC.DecoderNative" |
| 6 | - #include <membrane/log.h> |
| 7 6 | #include "stdint.h" |
| 7 | + #include <membrane/log.h> |
| 8 8 | |
| 9 9 | typedef struct _DecoderState UnifexNifState; |
| 10 10 | typedef UnifexNifState State; |
| 11 11 | |
| 12 | - struct _DecoderState |
| 13 | - { |
| 12 | + struct _DecoderState { |
| 14 13 | HANDLE_AACDECODER handle; |
| 15 14 | uint8_t *decoder_buffer; |
| 16 15 | int decoder_buffer_size; |
| @@ -1,7 +1,7 @@ | |
| 1 1 | #include "encoder.h" |
| 2 2 | |
| 3 3 | static const int SAMPLE_SIZE = 2; |
| 4 | - static const int MAX_AAC_BUFFER_SIZE = 8192; // TODO: Validate |
| 4 | + static const int MAX_AAC_BUFFER_SIZE = 8192; // TODO: Validate |
| 5 5 | |
| 6 6 | static const int PROFILE_AAC_HE = 5; |
| 7 7 | static const int PROFILE_AAC_HE_v2 = 29; |
| @@ -9,7 +9,8 @@ static const int PROFILE_MPEG2_AAC_HE = 132; | |
| 9 9 | |
| 10 10 | /** |
| 11 11 | * AAC Encoder implementation. |
| 12 | - * Heavily inspired by https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libfdk-aacenc.c |
| 12 | + * Heavily inspired by |
| 13 | + * https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libfdk-aacenc.c |
| 13 14 | */ |
| 14 15 | |
| 15 16 | /** |
| @@ -17,55 +18,59 @@ static const int PROFILE_MPEG2_AAC_HE = 132; | |
| 17 18 | */ |
| 18 19 | char *get_error_message(AACENC_ERROR err) { |
| 19 20 | switch (err) { |
| 20 | - case AACENC_OK: |
| 21 | - return "No error"; |
| 22 | - case AACENC_INVALID_HANDLE: |
| 23 | - return "Invalid handle"; |
| 24 | - case AACENC_MEMORY_ERROR: |
| 25 | - return "Memory allocation error"; |
| 26 | - case AACENC_UNSUPPORTED_PARAMETER: |
| 27 | - return "Unsupported parameter"; |
| 28 | - case AACENC_INVALID_CONFIG: |
| 29 | - return "Invalid config"; |
| 30 | - case AACENC_INIT_ERROR: |
| 31 | - return "Initialization error"; |
| 32 | - case AACENC_INIT_AAC_ERROR: |
| 33 | - return "AAC library initialization error"; |
| 34 | - case AACENC_INIT_SBR_ERROR: |
| 35 | - return "SBR library initialization error"; |
| 36 | - case AACENC_INIT_TP_ERROR: |
| 37 | - return "Transport library initialization error"; |
| 38 | - case AACENC_INIT_META_ERROR: |
| 39 | - return "Metadata library initialization error"; |
| 40 | - case AACENC_ENCODE_ERROR: |
| 41 | - return "Encoding error"; |
| 42 | - case AACENC_ENCODE_EOF: |
| 43 | - return "End of file"; |
| 44 | - default: |
| 45 | - return "Unknown error"; |
| 21 | + case AACENC_OK: |
| 22 | + return "No error"; |
| 23 | + case AACENC_INVALID_HANDLE: |
| 24 | + return "Invalid handle"; |
| 25 | + case AACENC_MEMORY_ERROR: |
| 26 | + return "Memory allocation error"; |
| 27 | + case AACENC_UNSUPPORTED_PARAMETER: |
| 28 | + return "Unsupported parameter"; |
| 29 | + case AACENC_INVALID_CONFIG: |
| 30 | + return "Invalid config"; |
| 31 | + case AACENC_INIT_ERROR: |
| 32 | + return "Initialization error"; |
| 33 | + case AACENC_INIT_AAC_ERROR: |
| 34 | + return "AAC library initialization error"; |
| 35 | + case AACENC_INIT_SBR_ERROR: |
| 36 | + return "SBR library initialization error"; |
| 37 | + case AACENC_INIT_TP_ERROR: |
| 38 | + return "Transport library initialization error"; |
| 39 | + case AACENC_INIT_META_ERROR: |
| 40 | + return "Metadata library initialization error"; |
| 41 | + case AACENC_ENCODE_ERROR: |
| 42 | + return "Encoding error"; |
| 43 | + case AACENC_ENCODE_EOF: |
| 44 | + return "End of file"; |
| 45 | + default: |
| 46 | + return "Unknown error"; |
| 46 47 | } |
| 47 48 | } |
| 48 49 | |
| 49 50 | /** |
| 50 51 | * Initializes AAC Encoder and returns State resource. |
| 51 | - * |
| 52 | + * |
| 52 53 | * Expects: |
| 53 | - * - channels - Number of channels. For now, only supports either 1 or 2 channels. |
| 54 | + * - channels - Number of channels. For now, only supports either 1 or 2 |
| 55 | + * channels. |
| 54 56 | * - sample_rate - Sample rate. |
| 55 57 | * - aot - Audio Object Type. |
| 56 | - * - bitrate_mode - 0 for CBR, 1-5 for VBR mode. See: http://wiki.hydrogenaud.io/index.php?title=Fraunhofer_FDK_AAC#Bitrate_Modes |
| 57 | - * |
| 58 | + * - bitrate_mode - 0 for CBR, 1-5 for VBR mode. See: |
| 59 | + * http://wiki.hydrogenaud.io/index.php?title=Fraunhofer_FDK_AAC#Bitrate_Modes |
| 60 | + * |
| 58 61 | * On success, returns {:ok, encoder_state} |
| 59 62 | * In case of error, returns: |
| 60 63 | * - {:error, reason} |
| 61 64 | */ |
| 62 | - UNIFEX_TERM create(UnifexEnv *env, int channels, int sample_rate, int aot, int bitrate_mode, int bitrate) { |
| 65 | + UNIFEX_TERM create(UnifexEnv *env, int channels, int sample_rate, int aot, |
| 66 | + int bitrate_mode, int bitrate) { |
| 63 67 | State *state = unifex_alloc_state(env); |
| 64 68 | state->channels = channels; |
| 65 69 | |
| 66 70 | AACENC_ERROR err; |
| 67 71 | CHANNEL_MODE channel_mode; |
| 68 | - // See: https://wiki.multimedia.cx/index.php/Understanding_AAC#Frames_And_Syntax_Elements |
| 72 | + // See: |
| 73 | + // https://wiki.multimedia.cx/index.php/Understanding_AAC#Frames_And_Syntax_Elements |
| 69 74 | int sce = 0, cpe = 0; |
| 70 75 | |
| 71 76 | // Initialize AAC Encoder handle |
| @@ -98,23 +103,24 @@ UNIFEX_TERM create(UnifexEnv *env, int channels, int sample_rate, int aot, int b | |
| 98 103 | |
| 99 104 | // Set channels configuration |
| 100 105 | switch (channels) { |
| 101 | - case 1: |
| 102 | - channel_mode = MODE_1; |
| 103 | - sce = 1; |
| 104 | - cpe = 0; |
| 105 | - break; |
| 106 | - case 2: |
| 107 | - channel_mode = MODE_2; |
| 108 | - sce = 0; |
| 109 | - cpe = 1; |
| 110 | - break; |
| 111 | - default: |
| 112 | - MEMBRANE_WARN(env, "AAC: Unsupported number of channels: %d", channels); |
| 113 | - return create_result_error(env, get_error_message(err)); |
| 106 | + case 1: |
| 107 | + channel_mode = MODE_1; |
| 108 | + sce = 1; |
| 109 | + cpe = 0; |
| 110 | + break; |
| 111 | + case 2: |
| 112 | + channel_mode = MODE_2; |
| 113 | + sce = 0; |
| 114 | + cpe = 1; |
| 115 | + break; |
| 116 | + default: |
| 117 | + MEMBRANE_WARN(env, "AAC: Unsupported number of channels: %d", channels); |
| 118 | + return create_result_error(env, get_error_message(err)); |
| 114 119 | } |
| 115 120 | err = aacEncoder_SetParam(state->handle, AACENC_CHANNELMODE, channel_mode); |
| 116 121 | if (err != AACENC_OK) { |
| 117 | - MEMBRANE_WARN(env, "AAC: Unable to set channel mode %d: %x\n", channel_mode, err); |
| 122 | + MEMBRANE_WARN(env, "AAC: Unable to set channel mode %d: %x\n", channel_mode, |
| 123 | + err); |
| 118 124 | return create_result_error(env, get_error_message(err)); |
| 119 125 | } |
| 120 126 | |
| @@ -128,7 +134,9 @@ UNIFEX_TERM create(UnifexEnv *env, int channels, int sample_rate, int aot, int b | |
| 128 134 | if (bitrate_mode) { |
| 129 135 | // VBR |
| 130 136 | if (bitrate_mode < 1 || bitrate_mode > 5) { |
| 131 | - MEMBRANE_WARN(env, "AAC: Unable to set VBR mode: %d. VBR quality should be 1-5\n", bitrate_mode); |
| 137 | + MEMBRANE_WARN( |
| 138 | + env, "AAC: Unable to set VBR mode: %d. VBR quality should be 1-5\n", |
| 139 | + bitrate_mode); |
| 132 140 | return create_result_error(env, "invalid_vbr"); |
| 133 141 | } |
| 134 142 | err = aacEncoder_SetParam(state->handle, AACENC_BITRATEMODE, bitrate_mode); |
| @@ -138,14 +146,14 @@ UNIFEX_TERM create(UnifexEnv *env, int channels, int sample_rate, int aot, int b | |
| 138 146 | } |
| 139 147 | } else { |
| 140 148 | // CBR |
| 141 | - // If bitrate is not specified by the user, this will estimate the bitrate, following the "rule of thumb" |
| 142 | - // described here: https://trac.ffmpeg.org/wiki/Encode/AAC#fdk_cbr |
| 143 | - // This is based on: https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libfdk-aacenc.c#L245 |
| 149 | + // If bitrate is not specified by the user, this will estimate the bitrate, |
| 150 | + // following the "rule of thumb" described here: |
| 151 | + // https://trac.ffmpeg.org/wiki/Encode/AAC#fdk_cbr This is based on: |
| 152 | + // https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/libfdk-aacenc.c#L245 |
| 144 153 | if (!bitrate) { |
| 145 154 | bitrate = (96 * sce + 128 * cpe) * sample_rate / 44; |
| 146 155 | } |
| 147 | - if (aot == PROFILE_AAC_HE || |
| 148 | - aot == PROFILE_AAC_HE_v2 || |
| 156 | + if (aot == PROFILE_AAC_HE || aot == PROFILE_AAC_HE_v2 || |
| 149 157 | aot == PROFILE_MPEG2_AAC_HE) { |
| 150 158 | bitrate /= 2; |
| 151 159 | } |
| @@ -176,18 +184,20 @@ UNIFEX_TERM create(UnifexEnv *env, int channels, int sample_rate, int aot, int b | |
| 176 184 | |
| 177 185 | /** |
| 178 186 | * Encodes one input frame. |
| 179 | - * |
| 187 | + * |
| 180 188 | * Expects: |
| 181 189 | * - Buffer to encoder |
| 182 190 | * - Native resource |
| 183 191 | * as arguments |
| 184 | - * |
| 192 | + * |
| 185 193 | * Returns on of: |
| 186 194 | * - {:ok, {encoded_frame}} - Encoded AAC frame |
| 187 | - * - {:error, :no_data} - When supplied input buffer does not contain enough data to encode a single frame |
| 195 | + * - {:error, :no_data} - When supplied input buffer does not contain enough |
| 196 | + * data to encode a single frame |
| 188 197 | * - {:error, reason} - When native encoding failed |
| 189 198 | */ |
| 190 | - UNIFEX_TERM encode_frame(UnifexEnv *env, UnifexPayload *in_payload, State *state) { |
| 199 | + UNIFEX_TERM encode_frame(UnifexEnv *env, UnifexPayload *in_payload, |
| 200 | + State *state) { |
| 191 201 | UNIFEX_TERM res; |
| 192 202 | AACENC_ERROR err; |
| 193 203 | |
| @@ -242,8 +252,9 @@ UNIFEX_TERM encode_frame(UnifexEnv *env, UnifexPayload *in_payload, State *state | |
| 242 252 | return encode_frame_result_error_no_data(env); |
| 243 253 | } |
| 244 254 | |
| 245 | - UnifexPayload *out_payload = unifex_payload_alloc(env, UNIFEX_PAYLOAD_BINARY, out_buffer_size); |
| 246 | - memcpy(out_payload->data, state->aac_buffer, out_buffer_size); |
| 255 | + UnifexPayload *out_payload = |
| 256 | + unifex_payload_alloc(env, UNIFEX_PAYLOAD_BINARY, out_args.numOutBytes); |
| 257 | + memcpy(out_payload->data, state->aac_buffer, out_args.numOutBytes); |
| 247 258 | res = encode_frame_result_ok(env, out_payload); |
| 248 259 | unifex_payload_release_ptr(&out_payload); |
| 249 260 | return res; |
| @@ -55,4 +55,4 @@ | |
| 55 55 | {<<"optional">>,false}, |
| 56 56 | {<<"repository">>,<<"hexpm">>}, |
| 57 57 | {<<"requirement">>,<<"~> 0.2.0">>}]]}. |
| 58 | - {<<"version">>,<<"0.2.0">>}. |
| 58 | + {<<"version">>,<<"0.2.1">>}. |
Loading more files…