FFMPEG音频解码和绘制波形

时间:2016-04-05 11:41:02

标签: c++ audio ffmpeg

我正在尝试解码音频并使用ffmpeg绘制波形,输入音频数据为AV_SAMPLE_FMT_S16P,基本上我正在按照教程here进行操作,并且音频播放正常{{3} 3}}。现在我需要使用解码数据绘制波形,目前我正在编写左右声道以分离csv文件并在excel上绘图。但是波形与使用相同音频剪辑的Audacity中显示的波形不同。当我分析写在csv上的值时,大多数值都接近uint16_t(65535)的最大值,但是还有一些其他较低的值,但多数是高峰值。

这是源代码,

    const char* input_filename="/home/user/Music/Clip.mp3";
    av_register_all();
    AVFormatContext* container=avformat_alloc_context();
    if(avformat_open_input(&container,input_filename,NULL,NULL)<0){
        endApp("Could not open file");
    }

    if(avformat_find_stream_info(container, NULL)<0){
        endApp("Could not find file info");
    }

    av_dump_format(container,0,input_filename,false);

    int stream_id=-1;
    int i;
    for(i=0;i<container->nb_streams;i++){
        if(container->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){
            stream_id=i;
            break;
        }
    }
    if(stream_id==-1){
        endApp("Could not find Audio Stream");
    }

    AVDictionary *metadata=container->metadata;

    AVCodecContext *ctx=container->streams[stream_id]->codec;
    AVCodec *codec=avcodec_find_decoder(ctx->codec_id);

    if(codec==NULL){
        endApp("cannot find codec!");
    }

    if(avcodec_open2(ctx,codec,NULL)<0){
        endApp("Codec cannot be found");
    }



    AVPacket packet;
    av_init_packet(&packet);

    //AVFrame *frame=avcodec_alloc_frame();
    AVFrame *frame=av_frame_alloc();

    int buffer_size=AVCODEC_MAX_AUDIO_FRAME_SIZE+ FF_INPUT_BUFFER_PADDING_SIZE;

    // MSVC can't do variable size allocations on stack, ohgodwhy
    uint8_t *buffer = new uint8_t[buffer_size];
    packet.data=buffer;
    packet.size =buffer_size;

    int frameFinished=0;

    int plane_size;

    ofstream fileCh1,fileCh2;
    fileCh1.open ("ch1.csv");
    fileCh2.open ("ch2.csv");

    AVSampleFormat sfmt=ctx->sample_fmt;

    while(av_read_frame(container,&packet)>=0)
    {

        if(packet.stream_index==stream_id){
            int len=avcodec_decode_audio4(ctx,frame,&frameFinished,&packet);
            int data_size = av_samples_get_buffer_size(&plane_size, ctx->channels,
                                                frame->nb_samples,
                                                ctx->sample_fmt, 1);


            if(frameFinished){
                int write_p=0;
                // QTime t;
                switch (sfmt){

                    case AV_SAMPLE_FMT_S16P:

                        for (int nb=0;nb<plane_size/sizeof(uint16_t);nb++){
                            for (int ch = 0; ch < ctx->channels; ch++) {
                                if(ch==0)
                                    fileCh1 <<((uint16_t *) frame->extended_data[ch])[nb]<<"\n";
                                else if(ch==1)
                                    fileCh2 <<((uint16_t *) frame->extended_data[ch])[nb]<<"\n";
                            }
                        }

                        break;

                }
            } else {
                DBG("frame failed");
            }
        }


        av_free_packet(&packet);
    }
    fileCh1.close();
    fileCh2.close();
    avcodec_close(ctx);
    avformat_close_input(&container);
    delete buffer;
    return 0;

修改

我已经使用opencv附加了波形图像绘制,这里我将样本值缩放到0-255范围,并将值127取为0(Y轴)。现在为每个样本绘制线从(x,127)到(x,样本值),其中x = 1,2,3,......

libao

1 个答案:

答案 0 :(得分:2)

问题是当样本格式被签名时转换为fileCh1 <<((int16_t *) frame->extended_data[ch])[nb]<<"\n"; (AV_SAMPLE_FMT_S16P,其中S表示签名)。因此,-1将作为2147483648写入文件,依此类推。

要修复它,请更改以下行:

public class MyErrorHandler extends ValidationErrorHandler {
private final static Logger logger = Logger.getLogger(LoggingHandler.class);

public void warning(SAXParseException exception) throws SAXException {
    logger.warn("warning", exception);
}

public static String message = "";

public void error(SAXParseException exception) throws SAXException {
    logger.error("error", exception);
    message += exception.getMessage();
    throw new SAXParseException("my custom" + exception.getMessage(),null);
}

public void fatalError(SAXParseException exception) throws SAXException {
    logger.fatal("fatal error", exception);
    throw new SAXParseException("my custom" + exception.getMessage(),null);
}

为:

Sub red_font_cells()
    With Worksheets("Sheet1")
        'turn off AutoFilter if it is on
        If .AutoFilterMode Then .AutoFilterMode = False
        'set a CF rule for <Now
        With .Range(.Cells(2, "L"), .Cells(Rows.Count, "L").End(xlUp))
            .FormatConditions.Delete
            With .FormatConditions.Add(Type:=xlExpression, Formula1:="=$L2<NOW()")
                .Font.Color = vbRed
            End With
        End With
        'add an AutoFilter for red font cells
        With .Range(.Cells(1, "L"), .Cells(Rows.Count, "L").End(xlUp))
            .AutoFilter Field:=1, Criteria1:=vbRed, _
                        Operator:=xlFilterFontColor
        End With
        'deal with the red font cells
        With .Range(.Cells(2, "L"), .Cells(Rows.Count, "L").End(xlUp))
            If CBool(Application.Subtotal(103, .Cells)) Then
                With .SpecialCells(xlCellTypeVisible)
                    'select them (there are better ways to get things done)
                    '.Select
                    'copy them to sheet2 (do not need Select for this)
                    .Copy Destination:=Sheet2.Range("A1")
                    'delete them
                    .EntireRow.Delete
                End With
            End If
        End With
        'turn off AutoFilter
        If .AutoFilterMode Then .AutoFilterMode = False
    End With
End Sub