Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added improved audio resampling support.

  • Loading branch information...
commit 72c416972e5f01671d4b77d567281254fcd3f945 1 parent 8058391
Manuel Astudillo manast authored
Showing with 187 additions and 77 deletions.
  1. +52 −27 binding.gyp
  2. +127 −47 src/navresample.cpp
  3. +6 −1 src/navresample.h
  4. +2 −2 wscript
79 binding.gyp
View
@@ -1,30 +1,55 @@
{
- "targets": [
- {
- "target_name": "navcodec",
- "sources": [
- "src/navcodec.cpp",
- "src/navcodeccontext.cpp",
- "src/navframe.cpp",
- "src/navformat.cpp",
- "src/navstream.cpp",
+ "targets": [
+ {
+ "target_name": "navcodec",
+ "sources": [
+ "src/navcodec.cpp",
+ "src/navcodeccontext.cpp",
+ "src/navframe.cpp",
+ "src/navformat.cpp",
+ "src/navstream.cpp",
"src/navoutformat.cpp",
- "src/navpixformat.cpp",
- "src/navsws.cpp",
- "src/navcodecid.cpp",
- "src/navresample.cpp",
- "src/navaudiofifo.cpp",
- "src/navdictionary.cpp",
- "src/navthumbnail.cpp",
- "src/relocatemoov.cpp"
- ],
- "conditions": [
- ['OS=="linux"', {
- "cflags" : ["-g", "-D__STDC_CONSTANT_MACROS", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"],
- "libraries" : ["-lavcodec","-lavformat","-lswscale","-lavutil"]
- }]
- ],
- }
- ]
+ "src/navpixformat.cpp",
+ "src/navsws.cpp",
+ "src/navcodecid.cpp",
+ "src/navresample.cpp",
+ "src/navaudiofifo.cpp",
+ "src/navdictionary.cpp",
+ "src/navthumbnail.cpp",
+ "src/relocatemoov.cpp"
+ ],
+ "conditions": [
+ ['OS=="mac"', {
+ "cflags" : [
+ "-g",
+ "-D__STDC_CONSTANT_MACROS",
+ "-D_FILE_OFFSET_BITS=64",
+ "-D_LARGEFILE_SOURCE",
+ "-Wall"],
+ "libraries" : [
+ "-lavcodec",
+ "-lavformat",
+ "-lswscale",
+ "-lavresample",
+ "-lavutil"
+ ]
+ }],
+ ['OS=="linux"', {
+ "cflags" : [
+ "-g",
+ "-D__STDC_CONSTANT_MACROS",
+ "-D_FILE_OFFSET_BITS=64",
+ "-D_LARGEFILE_SOURCE",
+ "-Wall"],
+ "libraries" : [
+ "-lavcodec",
+ "-lavformat",
+ "-lswscale",
+ "-lavresample",
+ "-lavutil"
+ ]
+ }]
+ ],
+ }
+ ]
}
-
174 src/navresample.cpp
View
@@ -1,4 +1,4 @@
-/* Copyright(c) 2012 Optimal Bits Sweden AB. All rights reserved.
+/* Copyright(c) 2012-2013 Optimal Bits Sweden AB. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
@@ -26,8 +26,20 @@
using namespace v8;
-// Proper size?
-#define AUDIO_BUFFER_SIZE 256*1024
+// Cheap layout guessing
+int numChannesToLayout(int numChannels){
+ fprintf(stderr, "num channels: %i", numChannels);
+ switch(numChannels){
+ case 2: return AV_CH_LAYOUT_STEREO;
+ case 3: return AV_CH_LAYOUT_2POINT1;
+ case 4: return AV_CH_LAYOUT_3POINT1;
+ case 5: return AV_CH_LAYOUT_4POINT1;
+ case 6: return AV_CH_LAYOUT_5POINT1;
+ case 7: return AV_CH_LAYOUT_6POINT1;
+ case 8: return AV_CH_LAYOUT_7POINT1;
+ }
+ return AV_CH_LAYOUT_STEREO;
+}
NAVResample::NAVResample(){
pContext = NULL;
@@ -39,8 +51,7 @@ NAVResample::NAVResample(){
NAVResample::~NAVResample(){
printf("NAVResample destructor\n");
-// audio_resample_close(pContext); // Crash for some unknown reason...
- av_free(pAudioBuffer);
+ avresample_free(&pContext);
frame.Dispose();
}
@@ -82,6 +93,7 @@ Handle<Value> NAVResample::New(const Arguments& args) {
stream = Local<Object>::Cast(args[1]);
AVStream *pDstStream = (node::ObjectWrap::Unwrap<NAVStream>(stream))->pContext;
+ instance->pSrcStream = pSrcStream;
instance->pDstStream = pDstStream;
AVCodecContext *pSrcCodec = pSrcStream->codec;
@@ -90,31 +102,40 @@ Handle<Value> NAVResample::New(const Arguments& args) {
if((pSrcCodec->channels != pDstCodec->channels) ||
(pSrcCodec->sample_rate != pDstCodec->sample_rate) ||
(pSrcCodec->sample_fmt != pDstCodec->sample_fmt) || // Sample format is irrelevant or not?
- (pSrcCodec->bit_rate > pDstCodec->bit_rate)){ // Bit rate is irrelevant here.
+ (pSrcCodec->bit_rate > pDstCodec->bit_rate)){
- instance->pContext = av_audio_resample_init(pDstCodec->channels, pSrcCodec->channels,
- pDstCodec->sample_rate, pSrcCodec->sample_rate,
- pDstCodec->sample_fmt, pSrcCodec->sample_fmt,
- 16, 10, 0, 0.8 );
+ instance->pContext = avresample_alloc_context();
if(instance->pContext == NULL) {
return ThrowException(Exception::TypeError(String::New("Could not init resample context")));
}
-
+
+ {
+ AVAudioResampleContext *avr = instance->pContext;
+
+ // TODO: Decide Channel layout based on input and output number of channels.
+ av_opt_set_int(avr, "in_channel_layout", numChannesToLayout(pSrcCodec->channels), 0);
+ av_opt_set_int(avr, "out_channel_layout", numChannesToLayout(pDstCodec->channels), 0);
+
+ av_opt_set_int(avr, "in_sample_rate", pSrcCodec->sample_rate, 0);
+ av_opt_set_int(avr, "in_sample_fmt", pSrcCodec->sample_fmt, 0);
+
+ av_opt_set_int(avr, "out_sample_rate", pDstCodec->sample_rate, 0);
+ av_opt_set_int(avr, "out_sample_fmt", pDstCodec->sample_fmt, 0);
+
+ if(avresample_open(instance->pContext)){
+ return ThrowException(Exception::TypeError(String::New("Could not open resampler")));
+ }
+ }
+
instance->pFrame = avcodec_alloc_frame();
if (!instance->pFrame){
return ThrowException(Exception::TypeError(String::New("Error Allocating AVFrame")));
}
-
- instance->pAudioBuffer = (uint8_t*) av_mallocz(AUDIO_BUFFER_SIZE);
- if (!instance->pAudioBuffer){
- av_freep(&(instance->pFrame));
- return ThrowException(Exception::TypeError(String::New("Error Allocating Audio Buffer")));
- }
-
+
instance->frame = Persistent<Object>::New(NAVFrame::New(instance->pFrame));
-
instance->passthrough = false;
}
+
return self;
}
@@ -130,9 +151,7 @@ Handle<Value> NAVResample::Convert(const Arguments& args) {
srcFrame = Local<Array>::Cast(args[0]);
NAVResample* instance = UNWRAP_OBJECT(NAVResample, args);
-
- // TODO: check that src frame is really compatible with this converter.
-
+
if(instance->passthrough){
return srcFrame;
} else {
@@ -144,35 +163,96 @@ Handle<Value> NAVResample::Convert(const Arguments& args) {
instance->pFrame->quality = 1;
instance->pFrame->pts = pSrcFrame->pts;
- instance->pFrame->format = AV_SAMPLE_FMT_S16;
-
- int nb_samples = audio_resample (instance->pContext,
- (short int*) instance->pAudioBuffer,
- (short int*) pSrcFrame->data[0],
- pSrcFrame->nb_samples);
-
- if(nb_samples<0) {
- return ThrowException(Exception::TypeError(String::New("Failed frame conversion")));
- }
-
- instance->pFrame->nb_samples = nb_samples;
-
- int size = nb_samples *
- pCodecContext->channels *
- av_get_bytes_per_sample(pCodecContext->sample_fmt);
+ //instance->pFrame->format = AV_SAMPLE_FMT_S16; // needed?
- int ret = avcodec_fill_audio_frame(instance->pFrame,
- pCodecContext->channels,
- pCodecContext->sample_fmt,
- instance->pAudioBuffer,
- size,
- 1);
- if(ret<0) {
- return ThrowException(Exception::TypeError(String::New("Failed filling frame")));
+ {
+ AVAudioResampleContext *avr = instance->pContext;
+
+ uint8_t *output;
+ int out_linesize;
+
+ int nb_samples = avresample_available(avr) +
+ av_rescale_rnd(avresample_get_delay(avr) +
+ pSrcFrame->nb_samples,
+ pCodecContext->sample_rate,
+ instance->pSrcStream->codec->sample_rate,
+ AV_ROUND_UP);
+ av_samples_alloc(&output,
+ &out_linesize,
+ pCodecContext->channels,
+ nb_samples,
+ pCodecContext->sample_fmt,
+ 0);
+ if(output == NULL) {
+ return ThrowException(Exception::TypeError(String::New("Failed allocating output samples buffer")));
+ }
+
+ nb_samples = avresample_convert(avr,
+ &output,
+ out_linesize,
+ nb_samples,
+ pSrcFrame->data,
+ pSrcFrame->linesize[0],
+ pSrcFrame->nb_samples);
+ int size = nb_samples *
+ pCodecContext->channels *
+ av_get_bytes_per_sample(pCodecContext->sample_fmt);
+/*
+ needed_size = av_samples_get_buffer_size(NULL,
+ pCodecContext->channels,
+ frame->nb_samples, sample_fmt,
+*/
+ instance->pFrame->nb_samples = nb_samples;
+
+ int ret = avcodec_fill_audio_frame(instance->pFrame,
+ pCodecContext->channels,
+ pCodecContext->sample_fmt,
+ output,
+ size,
+ 1);
+ if(ret<0) {
+ fprintf(stderr, "avcodec_fill_audio_frame returned %i\n", ret);
+ return ThrowException(Exception::TypeError(String::New("Failed filling frame")));
+ }
+ av_freep(&output);
}
-
+
instance->pFrame->owner = instance->pDstStream->codec;
+
return instance->frame;
}
}
+// Available layouts:
+/*
+ AV_CH_LAYOUT_5POINT1
+ AV_CH_LAYOUT_2_1
+ AV_CH_LAYOUT_2_2
+ AV_CH_LAYOUT_2POINT1
+ AV_CH_LAYOUT_3POINT1
+ AV_CH_LAYOUT_4POINT0
+ AV_CH_LAYOUT_4POINT1
+ AV_CH_LAYOUT_5POINT0
+ AV_CH_LAYOUT_5POINT0_BACK
+ AV_CH_LAYOUT_5POINT1
+ AV_CH_LAYOUT_5POINT1_BACK
+ AV_CH_LAYOUT_6POINT0
+ AV_CH_LAYOUT_6POINT0_FRONT
+ AV_CH_LAYOUT_6POINT1
+ AV_CH_LAYOUT_6POINT1_BACK
+ AV_CH_LAYOUT_6POINT1_FRONT
+ AV_CH_LAYOUT_7POINT0
+ AV_CH_LAYOUT_7POINT0_FRONT
+ AV_CH_LAYOUT_7POINT1
+ AV_CH_LAYOUT_7POINT1_WIDE
+ AV_CH_LAYOUT_7POINT1_WIDE_BACK
+ AV_CH_LAYOUT_HEXAGONAL
+ AV_CH_LAYOUT_MONO
+ AV_CH_LAYOUT_OCTAGONAL
+ AV_CH_LAYOUT_QUAD
+ AV_CH_LAYOUT_STEREO
+ AV_CH_LAYOUT_STEREO_DOWNMIX
+ AV_CH_LAYOUT_SURROUND
+*/
+
+
7 src/navresample.h
View
@@ -30,13 +30,17 @@
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
+#include <libavresample/avresample.h>
+#include <libavutil/opt.h>
+#include <libavutil/error.h>
}
using namespace v8;
class NAVResample : node::ObjectWrap {
private:
- struct ReSampleContext *pContext;
+ //struct ReSampleContext *pContext;
+ AVAudioResampleContext *pContext;
AVFrame *pFrame;
@@ -46,6 +50,7 @@ class NAVResample : node::ObjectWrap {
bool passthrough;
+ AVStream *pSrcStream;
AVStream *pDstStream;
4 wscript
View
@@ -12,7 +12,7 @@ def configure(conf):
def build(bld):
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
obj.cxxflags = ["-g", "-D__STDC_CONSTANT_MACROS", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
- obj.linkflags = ["-lavcodec","-lavformat","-lswscale","-lavutil"]
+ obj.linkflags = ["-lavcodec","-lavformat","-lswscale","-lavutil", "-lavresample"]
obj.target = "navcodec"
obj.source = ["src/navcodec.cpp", "src/navcodeccontext.cpp", "src/navframe.cpp", "src/navformat.cpp", "src/navstream.cpp", "src/navoutformat.cpp","src/navpixformat.cpp", "src/navsws.cpp", "src/navcodecid.cpp", "src/navresample.cpp", "src/navaudiofifo.cpp", "src/navdictionary.cpp", "src/navthumbnail.cpp", "src/relocatemoov.cpp"]
- obj.uselib = ['libavcodec', 'libavformat', 'libswscale','-lavutil']
+ obj.uselib = ['libavcodec', 'libavformat', 'libswscale','-lavutil', '-lavresample']
Please sign in to comment.
Something went wrong with that request. Please try again.