懂ffmpeg的大哥帮帮忙

zyt138 2010-04-29 02:41:16
这个是从CSDN下载来的,某大哥封装ffmpeg的东西变成了自己的音频转换ffmpegproxy.dll文件
本人才学了C++一年多,被要求做个音频转换的东西出来!!!!!
第一个文件
ffmpeg.h

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include "libavutil/avstring.h"
#include "libavformat/avformat.h"
#include "libavformat/rtsp.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavcodec/opt.h"
#include <libavcodec/avcodec.h>
#pragma comment(lib, "avcodec.lib")
#include <libavformat/avformat.h>
#pragma comment(lib, "avformat.lib")
#include <libswscale/swscale.h>
#pragma comment(lib, "swscale.lib")
#include <libavutil/mem.h>
#include <libavutil/fifo.h>
#pragma comment(lib, "avutil.lib")
#ifdef __cplusplus
}
#endif
#undef exit

void debug_string(const char *err_msg, ...)
{
}

int ffmpeg_conver_audio(const char* input_file, const char* output_file, int samples_rate, int channel)
{
AVFormatContext *infmt_ctx;

int i = 0;

//////////////////////// 初始化 ////////////////////////
avcodec_register_all();
avdevice_register_all();
av_register_all();

//////////////////////// 输入 ////////////////////////
infmt_ctx = av_alloc_format_context();

//打开输入文件
if(av_open_input_file(&infmt_ctx, input_file, NULL, 0, NULL)!=0)
{
debug_string("can't open input file\n");
return -1;
}

//取出流信息
if(av_find_stream_info(infmt_ctx) <0)
{
debug_string("can't find suitable codec parameters\n");
return -2;
}

//dump_format(infmt_ctx, 0, input_file, 0); //列出输入文件的相关流信息

// 查找音频流信息
int audioindex=-1;
for(unsigned int j = 0; j < infmt_ctx->nb_streams; j++)
{
if(infmt_ctx->streams[j]->codec->codec_type == CODEC_TYPE_AUDIO)
{
audioindex=j;
break;
}
}

if(audioindex == -1) //没有找到音频流
{
debug_string("can't find audio stream\n");
return -3;
}

AVCodecContext *incode_ctx;
AVCodec *incodec;

incode_ctx = infmt_ctx->streams[audioindex]->codec;

//找到合适的音频解码器
incodec = avcodec_find_decoder(incode_ctx->codec_id);
if(incodec == NULL)
{
debug_string("can't find suitable audio decoder\n");
return -4;
}

//打开该音频解码器
if(avcodec_open(incode_ctx, incodec) < 0)
{
debug_string("can't open the audio decoder\n");
return -5;
}

//////////////////////// 输出 ////////////////////////

/* 解析输出文件的格式 */
AVOutputFormat *outfmt = guess_format(NULL, output_file, NULL);
if (!outfmt) {
printf("Could not deduce output format from file extension: using MPEG.\n");
outfmt = guess_format("mpeg", NULL, NULL);
}
if (!outfmt) {
debug_string("Could not find suitable output format\n");
return -6;
}

outfmt->audio_codec = CODEC_ID_MP3;

/* allocate the output media context */
AVFormatContext *outfmt_ctx = av_alloc_format_context();
if (!outfmt_ctx) {
debug_string("Memory error\n");
return -7;
}

/* 保存输出文件的格式 */
outfmt_ctx->oformat = outfmt;
snprintf(outfmt_ctx->filename, sizeof(outfmt_ctx->filename), "%s", output_file);

/* add the audio and video streams using the default format codecs and initialize the codecs */

/* 输出文件的视频流编码器ID */
AVCodecContext *outcode_ctx;
AVCodec *outcodec;
AVStream *audio_st = NULL/*, *video_st*/;
//double audio_pts, video_pts;

//if (outfmt->video_codec != CODEC_ID_NONE) {
// video_st = add_video_stream(outfmt_ctx, outfmt->video_codec);
//}

/* 输出文件的音频流编码器ID */
if (outfmt->audio_codec != CODEC_ID_NONE) {
audio_st = av_new_stream(outfmt_ctx, 1);

outcode_ctx = audio_st->codec;
outcode_ctx->codec_id = outfmt->audio_codec;
outcode_ctx->codec_type = CODEC_TYPE_AUDIO;

//oAcc->bit_rate =inCodecCtx->bit_rate ;
outcode_ctx->sample_rate = samples_rate > 0 ? samples_rate : incode_ctx->sample_rate;
outcode_ctx->channels = channel > 0 ? channel : incode_ctx->channels;
outcode_ctx->block_align = incode_ctx->block_align;
if(outcode_ctx->block_align == 1 && outcode_ctx->codec_id == CODEC_ID_MP3)
outcode_ctx->block_align = 0;
}
/* 设置输出参数 */
if (av_set_parameters(outfmt_ctx, NULL) < 0) {
debug_string("Invalid output format parameters\n");
return -8;
}

/* 列出输出文件的格式信息 */
dump_format(outfmt_ctx, 0, output_file, 1);

strcpy(outfmt_ctx->title, infmt_ctx->title);
strcpy(outfmt_ctx->author, infmt_ctx->author);
strcpy(outfmt_ctx->copyright, infmt_ctx->copyright);
strcpy(outfmt_ctx->comment, infmt_ctx->comment);
strcpy(outfmt_ctx->album, infmt_ctx->album);
outfmt_ctx->year = infmt_ctx->year;
outfmt_ctx->track = infmt_ctx->track;
strcpy(outfmt_ctx->genre, infmt_ctx->genre);

//dump_format(oc,0,output_file_name,1);//列出输出文件的相关流信息
//找到合适的音频编码器
outcodec = avcodec_find_encoder(outfmt_ctx->oformat->audio_codec);//(CODEC_ID_AAC);
if(!outcodec)
{
debug_string("can't find suitable audio encoder\n");
return -9;
}

if(avcodec_open(outcode_ctx, outcodec) <0) //////////////////////////////////////////////////
{
debug_string("can't open the output audio codec");
return -10;
}

/* now that all the parameters are set, we can open the audio and
video codecs and allocate the necessary encode buffers */
//if (video_st)
// open_video(outfmt_ctx, video_st);

/* 打开音频编码器 */
uint8_t * pktdata = NULL;
int pktsize = 0;
int outSampleSize;
int audioSize = 128 * 1024 * 4; //AVCODEC_MAX_AUDIO_FRAME_SIZE;//audio_outbuf_size/incode_ctx->channels;
if (outcode_ctx->frame_size <= 1)
{
switch(outcode_ctx->codec_id)
{
case CODEC_ID_PCM_S32LE:
case CODEC_ID_PCM_S32BE:
case CODEC_ID_PCM_U32LE:
case CODEC_ID_PCM_U32BE:
audioSize <<= 1;
break;
case CODEC_ID_PCM_S24LE:
case CODEC_ID_PCM_S24BE:
case CODEC_ID_PCM_U24LE:
case CODEC_ID_PCM_U24BE:
case CODEC_ID_PCM_S24DAUD:
audioSize = audioSize / 2 * 3;
break;
case CODEC_ID_PCM_S16LE:
case CODEC_ID_PCM_S16BE:
case CODEC_ID_PCM_U16LE:
case CODEC_ID_PCM_U16BE:
break;
default:
audioSize >>= 1;
break;
}

outSampleSize = audioSize * 2 * outcode_ctx->channels;
}
else
{
outSampleSize = outcode_ctx->frame_size * 2 * outcode_ctx->channels;
}

int audio_outbuf_size = AVCODEC_MAX_AUDIO_FRAME_SIZE; //FF_MIN_BUFFER_SIZE; //outSampleSize;//inputSampleSize;//
uint8_t *audio_outbuf = (uint8_t *)av_malloc(audio_outbuf_size); // *2 * oAcc->channels);

int samples_size_ptr = AVCODEC_MAX_AUDIO_FRAME_SIZE;
short *samples = (short*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE);
uint8_t *pSamples;

/* 如果输出文件不存在, 则创建输出文件 */
if (!(outfmt->flags & AVFMT_NOFILE)) {
if (url_fopen(&outfmt_ctx->pb, output_file, URL_WRONLY) < 0) {
debug_string("Could not open '%s'\n", output_file);
return -11;
}
}

/* 写输出文件的头 */
av_write_header(outfmt_ctx);

AVFifoBuffer fifo;
av_fifo_init(&fifo, av_fifo_size(&fifo)+samples_size_ptr);

int len=0;

AVPacket packet;
av_init_packet(&packet);

while(av_read_frame(infmt_ctx, &packet) >= 0)//从输入文件中读取一个包
{
if(packet.stream_index == audioindex)
{
pktsize = packet.size;
pktdata = packet.data;

if (pktsize > 0)
{
//if(&packet)
//samples=(short *)av_fast_realloc(samples,&samples_size,FFMAX(packet.size*sizeof(*samples),AVCODEC_MAX_AUDIO_FRAME_SIZE));
samples_size_ptr = AVCODEC_MAX_AUDIO_FRAME_SIZE;
len = avcodec_decode_audio2(incode_ctx, samples, &samples_size_ptr, pktdata, pktsize);//若为音频包,解码该音频包
debug_string("源文件的帧数:%d\n", incode_ctx->frame_number);
if(len <0)
{
debug_string("while decode audio failure\n");
break;
};

if(samples_size_ptr <= 0)
{
debug_string("samples_size_ptr 小于0");
continue;
}

pSamples = (uint8_t *)samples;

av_fifo_realloc(&fifo, av_fifo_size(&fifo)+samples_size_ptr);
//av_fifo_generic_write(&fifo, samples, samples_size_ptr, NULL);
av_fifo_write(&fifo, pSamples, samples_size_ptr);

uint8_t *audio_buf = (uint8_t *)malloc(outSampleSize);
while (av_fifo_read(&fifo, audio_buf, outSampleSize) == 0)//(av_fifo_size(&fifo) > outSampleSize)
{
// 如果音频帧的大小小于FF_MIN_BUFFER_SIZE,编码函数将退出
if (audio_outbuf_size < FF_MIN_BUFFER_SIZE)
audio_outbuf_size = FF_MIN_BUFFER_SIZE;

AVPacket pkt;
av_init_packet(&pkt);

int ss = avcodec_encode_audio(outcode_ctx, audio_outbuf, audio_outbuf_size, (short *)audio_buf);
pkt.size = ss;

debug_string("输出文件的帧数:%d\n", outcode_ctx->frame_number);

// 时间戳在没有视频的情况下,实际上没有设置的必要
if (outcode_ctx->coded_frame && outcode_ctx->coded_frame->pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(outcode_ctx->coded_frame->pts, outcode_ctx->time_base, audio_st->time_base);

pkt.flags |= PKT_FLAG_KEY; // 设不设置好像都没有什么影响
pkt.stream_index = audio_st->index;// audioindex;
pkt.data = audio_outbuf;

if (pkt.size >0)
{
if (av_write_frame(outfmt_ctx, &pkt) != 0)
{
debug_string("Error while writing audio frame\n");
//return -12;
}
}

av_free_packet(&pkt);
}
}
}

// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}

/* write the trailer, if any */
av_write_trailer(outfmt_ctx);

avcodec_close(outcode_ctx);

/* free the streams */
for(i = 0; i < outfmt_ctx->nb_streams; i++) {
av_freep(&outfmt_ctx->streams[i]->codec);
av_freep(&outfmt_ctx->streams[i]);
}
if (!(outfmt->flags & AVFMT_NOFILE)) {
/* close the output file */
url_fclose(outfmt_ctx->pb);
}
av_free(outfmt_ctx);

avcodec_close(incode_ctx);
av_close_input_file(infmt_ctx);

return 0;
}


...全文
1163 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
ai812568962 2011-11-14
  • 打赏
  • 举报
回复
谢了...刚好用到了
wansbest 2011-11-11
  • 打赏
  • 举报
回复
不知道楼主还在不在,我也刚学ffmpeg。
return ffmpeg_conver_audio(input_file, output_file, samples_rate, channel);

这个函数很简单,input_file就是你要转换的音频文件,output_file就是转换完成后你要输出的文件,samples是

音频的采样率,channel是音频通道。

但我拿过去编译了下,发现这个函数本身就存在问题吧!

1:正常转换应该是根据output_file的后缀得出最终要使用什么编码器,但程序在中间直接就将编码器设置为MP3了。

2:samples_rate是音频的采样率,一般是根据输入文件来得,无需设置,所以不知道传这个进去做什么用,而且一旦设置错误就会导致找不到编码器。而输出文件的bit_rate是可以设置的,这个会决定输出文件的压缩率。但它这儿确没设置。

我将这些改了之后但还是不行,在av_fifo_read的时候,每次返回结果都是0,导致程序进入了死循环。查了下头文件,注释很少。基本意思就是说将之前写入的avfifobuffer里面的数据读出来,每次读buf_size个字节。后来去查源码,发现新版本都已经没有这个函数了。

没有再改了,再改下去跟我之前一个音频转换的代码就几乎一样了。

新手一个,也可能是水平不够没用好,期待高人指教!!!
brant_wong 2011-11-07
  • 打赏
  • 举报
回复
楼主这里 int result = addFun(input,output,0,0);
第三个参数是音频的采样率 例如22050,8000等
第四个参数是音频的声道数,一般是两个,写2就可以了
huangsw168 2011-10-31
  • 打赏
  • 举报
回复
这个代码谁能给我一份啊,邮箱269234154@qq.com
jnetzhou 2011-06-15
  • 打赏
  • 举报
回复
大哥,我也要!742408364@qq.com,thank you!
Q吹个大气球Q 2011-03-29
  • 打赏
  • 举报
回复
能否也给我一份代码,万分感谢了
huoppo 2011-03-17
  • 打赏
  • 举报
回复
我也留一个邮箱:huoppo@126.com
也给我一个,非常的感谢!
btzhu 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 dskit 的回复:]
引用 8 楼 btzhu 的回复:
引用 7 楼 dskit 的回复:
要看ffmpeg的文档,下面这个是唯一推荐:
http://www.ffmpeg.org/documentation.html


这位大哥 ,我想找你要代码,希望帮忙

留邮箱吧
[/Quote]
6471893@qq.com
dskit 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 btzhu 的回复:]
引用 7 楼 dskit 的回复:
要看ffmpeg的文档,下面这个是唯一推荐:
http://www.ffmpeg.org/documentation.html


这位大哥 ,我想找你要代码,希望帮忙
[/Quote]
留邮箱吧
btzhu 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 dskit 的回复:]
要看ffmpeg的文档,下面这个是唯一推荐:
http://www.ffmpeg.org/documentation.html
[/Quote]

这位大哥 ,我想找你要代码,希望帮忙
dskit 2010-04-29
  • 打赏
  • 举报
回复
要看ffmpeg的文档,下面这个是唯一推荐:
http://www.ffmpeg.org/documentation.html
ypb362148418 2010-04-29
  • 打赏
  • 举报
回复
说说什么问题,代码实在太长了,可以去开源社区看看别人写的代码
dskit 2010-04-29
  • 打赏
  • 举报
回复
我做过相关工作,可以找我要
zyt138 2010-04-29
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 dinjay 的回复:]
LZ....别这么贴代码,你看到这么多会是什么感受...下次注意吧....
int ffmpeg_conver_audio(const char* input_file, const char* output_file, int samples_rate, int channel)

input_file应该是要转换的文件名
output_file就是要输出的文件的文件名
这两个应该都是……
[/Quote]


多谢回复,我去查查
其实主要是第一个代码确实是太长了,不知道dll调用有没有成功
dinjay 2010-04-29
  • 打赏
  • 举报
回复
LZ....别这么贴代码,你看到这么多会是什么感受...下次注意吧....
int ffmpeg_conver_audio(const char* input_file, const char* output_file, int samples_rate, int channel)

input_file应该是要转换的文件名
output_file就是要输出的文件的文件名
这两个应该都是MPEG后缀的
samples_rate是抽样率....应该是转换时用到的参数,你去查查干嘛用的,估计是频率之类的
channel应该是大小吧,应该也是参数,你看看channel都在哪儿用了,好像就是size上用了
zyt138 2010-04-29
  • 打赏
  • 举报
回复
我感觉是ffmpegproxy.dll没有调用成功
zyt138 2010-04-29
  • 打赏
  • 举报
回复
第二个文件
ffmpegproxy.h

#ifdef FFMPEGPROXY_EXPORTS
#define FFMPEGPROXY_API __declspec(dllexport)
#else
#define FFMPEGPROXY_API __declspec(dllimport)
#endif

FFMPEGPROXY_API int __stdcall ConverAudio(const char*, const char*, int, int);


ffmpegproxy.cpp 第三个文件

#include "stdafx.h"
#include "ffmpegproxy.h"
#include "ffmpeg.h"

BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

// This is an example of an exported function.
FFMPEGPROXY_API int __stdcall ConverAudio(const char* input_file, const char* output_file, int samples_rate, int channel)
{
return ffmpeg_conver_audio(input_file, output_file, samples_rate, channel);
}



还有StdAfx.cpp 跟 StdAfx.h 忽略下





我自己写的调用dll,昨晚从深入浅出调用dll文章抄学来的,不知道有没有错?



#include <stdio.h>
#include <windows.h>
typedef int(*lpAddFun)(const char* input_file, const char* output_file, int samples_rate, int channel); //宏定义函数指针类型

int main()
{
char *input = "D:\\nunnally.wav";
char *output = "nunnally.flv";
HINSTANCE hDll; //DLL句柄
lpAddFun addFun; //函数指针
hDll = LoadLibrary("D:\\Backup\\我的文档\\double\\main\\ffmpegproxy.dll");
if (hDll != NULL)
{
addFun = (lpAddFun)GetProcAddress(hDll, "ConverAudio");
if (addFun != NULL)
{
int result = addFun(input,output,0,0);
printf("%d", result);
}
FreeLibrary(hDll);
}
return 0;
}


编译过去了,但是没反应啊!!!!!
ffmpeg_conver_audio(const char* input_file, const char* output_file, int samples_rate, int channel)
这个函数里面应该传什么??
看过一些ffmpeg用法文章,太难懂了。
有什么错了,求救!!!!!!

24,854

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧