注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

_

_

 
 
 

日志

 
 

This file is a part of the SWFer project.  

2013-03-16 21:43:55|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

?


/*


* This file is a part of the SWFer project.


*


* Copyright (C) 2012 Michael Bradshaw <mjbshaw@gmail.com>


*


* This program is free software; you can redistribute it and/or modify it


* under the terms of the GNU General Public License as published by the Free


* Software Foundation; either version 2 of the License, or (at your option)


* any later version.


*


* This program is distributed in the hope that it will be useful, but WITHOUT


* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or


* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for


* more details.


*


* You should have received a copy of the GNU General Public License along with


* this program; if not, write to the Free Software Foundation, Inc., 59 Temple


* Place, Suite 330, Boston, MA 02111-1307 USA


*


*/




#include "NewSimpleSound.hpp"


#include "ui_NewSimpleSound.h"




#include "SwfMainDisplay.hpp"




#include <iostream>




#include <swfer/SimpleSwf.hpp>


#include <swfer/SimpleSound.hpp>




#include <QFileDialog>




extern "C"


{


#include <libavformat/avformat.h>


#include <libswresample/swresample.h>


}




NewSimpleSound::NewSimpleSound(QWidget* parent) : QDialog(parent),


ui(new Ui::NewSimpleSound)


{


ui->setupUi(this);




connect(ui->selectFileButton, SIGNAL(pressed()), this, SLOT(selectFile()));


connect(ui->saveAsButton, SIGNAL(pressed()), this, SLOT(saveAs()));


connect(ui->cancelButton, SIGNAL(pressed()), this, SLOT(close()));




//swfer::SimpleSwf tmp1("../samples/UntitledTest.swf");


//swfer::SimpleSwf tmp2("../samples/zhacked.swf");


//swfer::SimpleSwf tmp3("../samples/nphacked.swf");


//swfer::SimpleSwf tmp4("../samples/TEST_WITH_PACKAGE.swf");


//swfer::SimpleSwf tmp5("../samples/TEST_NO_PACKAGE.swf");


}




NewSimpleSound::~NewSimpleSound()


{


delete ui;


}




struct Encoder


{


AVCodec* codec;


AVCodecContext* ctx;


AVFrame* frame;


int bufferSize;


uint16_t* samples;


std::size_t samplesInFrame;




int numSamplesEncoded;




Encoder()


{


samplesInFrame = 0;


numSamplesEncoded = 0;




codec = avcodec_find_encoder(AV_CODEC_ID_MP3);


if (!codec)


{


// error


std::cerr << "Could not find mp3 codec" << std::endl;


}




ctx = avcodec_alloc_context3(codec);




ctx->bit_rate = 64000; // TODO: ???




ctx->sample_fmt = AV_SAMPLE_FMT_S16;


// TODO: assert ctx->sample_fmt is in codec->sample_fmts




ctx->sample_rate = 44100;


// TODO: check codec->sample_rates


ctx->channel_layout = AV_CH_LAYOUT_STEREO;


// TODO: check codec->channel_layouts


ctx->channels = av_get_channel_layout_nb_channels(ctx->channel_layout);




if (avcodec_open2(ctx, codec, NULL) < 0)


{


// error


std::cerr << "Couldn't open codec" << std::endl;


}




frame = avcodec_alloc_frame();


if (!frame)


{


// error


std::cerr << "Couldn't allocate frame" << std::endl;


}




frame->nb_samples = ctx->frame_size;


frame->format = ctx->sample_fmt;


frame->channel_layout = ctx->channel_layout;




bufferSize = av_samples_get_buffer_size(NULL, ctx->channels,


ctx->frame_size, ctx->sample_fmt, 0);




samples = static_cast<uint16_t*>(av_malloc(bufferSize));


if (!samples)


{


// error


std::cerr << "Couldn't allocate samples buffer" << std::endl;


}




int ret = avcodec_fill_audio_frame(frame, ctx->channels, ctx->sample_fmt,


(const uint8_t*)samples, bufferSize, 0);


if (ret < 0)


{


// error


std::cerr << "Couldnt set up audio frame" << std::endl;


}


}




void processSamples(const char* buffer, int nbSamples)


{


for (int i = 0; i < nbSamples; ++i)


{


// 2 because 2 == sizeof(uint16_t)


samples[2 * samplesInFrame] = reinterpret_cast<const uint16_t*>(buffer)[2 * i];




for (int k = 1; k < ctx->channels; ++k)


{


samples[2 * samplesInFrame + k] = reinterpret_cast<const uint16_t*>(buffer)[2 * i + k];


}




++samplesInFrame;




if (samplesInFrame == ctx->frame_size)


{


encode();


}


}


}




void finish()


{


if (samplesInFrame > 0)


{


frame->nb_samples = samplesInFrame;


encode();


}




if (codec->capabilities & CODEC_CAP_DELAY)


{


AVPacket pkt;


av_init_packet(&pkt);


pkt.data = NULL;


pkt.size = 0;




int gotPacket = 0;


while (avcodec_encode_audio2(ctx, &pkt, NULL, &gotPacket) == 0 && gotPacket)


{


for (int i = 0; i < pkt.size; ++i)


{


data.push_back(pkt.data[i]);


}




av_free_packet(&pkt);


}


}




}




void encode()


{


AVPacket pkt;


av_init_packet(&pkt);


pkt.data = NULL;


pkt.size = 0;




int gotPacket = 0;


int ret = avcodec_encode_audio2(ctx, &pkt, frame, &gotPacket);


if (ret < 0)


{


// error


std::cerr << "Error encoding audio frame" << std::endl;


}


if (gotPacket)


{


for (int i = 0; i < pkt.size; ++i)


{


data.push_back(pkt.data[i]);


}




av_free_packet(&pkt);


}




numSamplesEncoded += samplesInFrame;


samplesInFrame = 0;


}




std::vector<char> data;


};




#include <fstream>




bool NewSimpleSound::encode(const QString& sourcePath, swfer::SimpleSound& ss)


{


Encoder encoder;




AVFrame* frame = avcodec_alloc_frame();


if (!frame)


{


std::cerr << "Error allocating the frame" << std::endl;


return false;


}




AVFormatContext* formatContext = NULL;


if (avformat_open_input(&formatContext, sourcePath.toStdString().c_str(), NULL, NULL) != 0)


{


av_free(frame);


std::cerr << "Error opening the file" << std::endl;


return false;


}




if (avformat_find_stream_info(formatContext, NULL) < 0)


{


av_free(frame);


avformat_close_input(&formatContext);


std::cerr << "Error finding the stream info" << std::endl;


return false;


}




AVStream* audioStream = NULL;


for (unsigned int i = 0; i < formatContext->nb_streams; ++i)


{


if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)


{


audioStream = formatContext->streams[i];


break;


}


}




if (audioStream == NULL)


{


av_free(frame);


avformat_close_input(&formatContext);


std::cerr << "Could not find any audio stream in the file" << std::endl;


return false;


}




AVCodecContext* codecContext = audioStream->codec;




codecContext->codec = avcodec_find_decoder(codecContext->codec_id);


if (codecContext->codec == NULL)


{


av_free(frame);


avformat_close_input(&formatContext);


std::cerr << "Couldn't find a proper decoder" << std::endl;


return false;


}


else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0)


{


av_free(frame);


avformat_close_input(&formatContext);


std::cerr << "Couldn't open the context with the decoder" << std::endl;


return false;


}




//std::cout << "This stream has " << codecContext->channels << " channels and a sample rate of " << codecContext->sample_rate << "Hz" << std::endl;


//std::cout << "The data is in the format " << av_get_sample_fmt_name(codecContext->sample_fmt) << std::endl;




int64_t outChannelLayout = AV_CH_LAYOUT_STEREO;


AVSampleFormat outSampleFormat = AV_SAMPLE_FMT_S16;


int outSampleRate = 44100;




// Note that AVCodecContext::channel_layout may or may not be set by libavcodec. Because of this,


// we won't use it, and will instead try to guess the layout from the number of channels.


SwrContext* swrContext = swr_alloc_set_opts(NULL,


outChannelLayout,


outSampleFormat,


outSampleRate,


av_get_default_channel_layout(codecContext->channels),


codecContext->sample_fmt,


codecContext->sample_rate,


0,


NULL);




if (swrContext == NULL)


{


av_free(frame);


avcodec_close(codecContext);


avformat_close_input(&formatContext);


std::cerr << "Couldn't create the SwrContext" << std::endl;


return false;


}




if (swr_init(swrContext) != 0)


{


av_free(frame);


avcodec_close(codecContext);


avformat_close_input(&formatContext);


swr_free(&swrContext);


std::cerr << "Couldn't initialize the SwrContext" << std::endl;


return false;


}




AVPacket packet;


av_init_packet(&packet);




// Read the packets in a loop


while (av_read_frame(formatContext, &packet) == 0)


{


if (packet.stream_index == audioStream->index)


{


// Create a copy of the packet that we can modify and manipulate


AVPacket decodingPacket = packet;




while (decodingPacket.size > 0)


{


// Try to decode the packet into a frame


int frameFinished = 0;


int result = avcodec_decode_audio4(codecContext, frame, &frameFinished, &decodingPacket);




if (result < 0 || frameFinished == 0)


{


break;


}




std::vector<unsigned char> buffer(2 * 44100 * 2);




unsigned char* outPtrs[SWR_CH_MAX] = {NULL};


outPtrs[0] = &buffer[0];




int numSamplesOut = swr_convert(swrContext,


outPtrs,


44100,


(const uint8_t**)frame->data,


frame->nb_samples);




encoder.processSamples((const char*)&buffer[0], numSamplesOut);




decodingPacket.size -= result;


decodingPacket.data += result;


}


}




// You *must* call av_free_packet() after each call to av_read_frame() or else you could leak memory


av_free_packet(&packet);


}




// Some codecs will cause frames to be buffered up in the decoding process. If the CODEC_CAP_DELAY flag


// is set, there can be buffered up frames that need to be flushed, so we'll do that


if (codecContext->codec->capabilities & CODEC_CAP_DELAY)


{


av_init_packet(&packet);


// Decode all the remaining frames in the buffer, until the end is reached


int frameFinished = 0;


while (avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet) >= 0 && frameFinished)


{


std::vector<unsigned char> buffer(2 * 44100 * 2);




unsigned char* outPtrs[SWR_CH_MAX] = {NULL};


outPtrs[0] = &buffer[0];




int numSamplesOut = swr_convert(swrContext,


outPtrs,


44100,


(const uint8_t**)frame->data,


frame->nb_samples);




encoder.processSamples((const char*)&buffer[0], numSamplesOut);


}


}




// swr_convert can buffer data up. Passing NULL and 0 into it will flush what's buffered out.


// You should do this at the very end. Alternatively, if you always want to get every sample


// out (i.e. you don't want it to buffer), you can do this after each call to swr_convert.


int numSamplesOut = 0;


do {


std::vector<unsigned char> buffer(2 * 44100 * 2);




unsigned char* pointers[SWR_CH_MAX] = {NULL};


pointers[0] = &buffer[0];




numSamplesOut = swr_convert(swrContext,


pointers,


44100,


NULL,


0);




encoder.processSamples((const char*)&buffer[0], numSamplesOut);


} while (numSamplesOut > 0);




//encoder.finish();




ss.format = swfer::MP3;


ss.samples = encoder.numSamplesEncoded;


ss.skip = audioStream->codec->delay + encoder.ctx->delay;


ss.data.swap(encoder.data);


ss.size = swfer::SAMPLE_16_BITS;


ss.layout = swfer::STEREO;


ss.rate = swfer::SAMPLE_44100_HZ;




// Clean up!


av_free(frame);


avcodec_close(codecContext);


avformat_close_input(&formatContext);


swr_free(&swrContext);


return true;


}




void NewSimpleSound::saveAs()


{


QString path = QFileDialog::getSaveFileName(this);


if (!path.isEmpty())


{


swfer::SimpleSound ss;


ss.className = ui->classNameLineEdit->text().toStdString();


ss.packageName = ui->packageNameLineEdit->text().toStdString();


ss.loop = ui->loopCheckBox->isChecked();


encode(ui->sourceFileLineEdit->text(), ss);




swfer::SimpleSwf swf;


swf.addSound(ss);


swf.save(path.toStdString());


}


}




void NewSimpleSound::selectFile()


{


QString path = QFileDialog::getOpenFileName(this);


if (!path.isEmpty())


{


ui->sourceFileLineEdit->setText(path);


}


}

?

Show detailsHide details

Change log

a58b55a5393c by Michael Bradshaw <mjbshaw> on Dec 24, 2012 Diff

Basic exporting works! (extremely fragile)

Go to:
/SWFer/NewSimpleSound.cpp/SWFer/NewSimpleSound.ui/SWFer/SWFer.vcxproj/libSWFer/ByteReader.cpp/libSWFer/ByteReader.hpp/libSWFer/ByteWriter.cpp/libSWFer/ByteWriter.hpp/libSWFer/Decode.cpp/libSWFer/Encode.cpp/libSWFer/Rect.hpp/libSWFer/SimpleSound.cpp/libSWFer/SimpleSound.hpp/libSWFer/SimpleSwf.cpp/libSWFer/Tags.hpp/libSWFer/libSWFer.vcxproj

Older revisions

This file is a part of the SWFer project. - redtea - 熠彩网络This file is a part of the SWFer project. - redtea - 熠彩网络40dca118bfdd by Michael Bradshaw <mjbshaw> on Oct 15, 2012 Diff

Fix type promotion when writing header

This file is a part of the SWFer project. - redtea - 熠彩网络This file is a part of the SWFer project. - redtea - 熠彩网络2ca0e187eaaa by Michael Bradshaw <mjbshaw> on Oct 14, 2012 Diff

Lots of changes...

All revisions of this file

File info

Size: 12517 bytes, 446 lines

View raw file

Terms - Privacy - Project Hosting Help

Powered by Google Project Hosting


Find open source projects...Create a project...
  评论这张
 
阅读(655)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017