本人之前写过一些用ffmpeg录制系统声音,麦克风声音的博客;比如ffmpeg录制系统声音
,由于采取的是ffmpeg自带的aac音频编码器,故最终的音频编码的格式一直是AV_SAMPLE_FMT_FLTP,即float平面模式,故在编码时,经常需要声音样例从packed模式转化为planar模式,故本人写过不少这样的代码:

uint8_t *audio_buf[2] = { 0 };
audio_buf[0] = (uint8_t *)frame_mic_encode->data[0];
audio_buf[1] = (uint8_t *)frame_mic_encode->data[1];int nb = swr_convert(m_pAudioConvertCtx, audio_buf, dst_nb_samples, (const uint8_t**)frame_mix->data, frame_mix->nb_samples);

现如今,janus里面的音频采取OPUS编码,采样位数为16,本人欲用ffmpeg将音频录制下来,若依然用AV_SAMPLE_FMT_FLTP,则由于此种格式采样位数为32,无疑增加了文件大小。故本人决定采取AV_SAMPLE_FMT_S16P格式,但是ffmpeg自带的aac音频编码器不支持这种格式,报下列错误:

aac @ 0x7fffb8072b30] [0m[1;31mSpecified sample format s16p is invalid or not supported

显然编码器不支持此种采样格式,编码器支持的采样格式可以通过下列代码进行枚举

int i = 0;
enum AVSampleFormat sampleFmt;
sampleFmt = m_pCodecEncode_Audio->sample_fmts[i];
while (sampleFmt != AV_SAMPLE_FMT_NONE)
{i++;sampleFmt = m_pCodecEncode_Audio->sample_fmts[i];
}

后面本人采取fdk_aac作为音频编码格式,发现其不支持AV_SAMPLE_FMT_S16P,而是支持AV_SAMPLE_FMT_S16,这个可以通过如下代码验证:

m_pCodecEncode_Audio = (AVCodec *)avcodec_find_encoder_by_name("libfdk_aac");m_pCodecEncodeCtx_Audio = avcodec_alloc_context3(m_pCodecEncode_Audio);
if (!m_pCodecEncodeCtx_Audio)
{break;
}int i = 0;
enum AVSampleFormat sampleFmt;
sampleFmt = m_pCodecEncode_Audio->sample_fmts[i];
while (sampleFmt != AV_SAMPLE_FMT_NONE)
{i++;sampleFmt = m_pCodecEncode_Audio->sample_fmts[i];
}

fdk_aac仅支持AV_SAMPLE_FMT_S16这一种样例格式。
很明显这是非平面模式,故对应的转换代码如下:

uint8_t *audio_buf[1] = { 0 };
audio_buf[0] = (uint8_t *)frame_mic_encode->data[0];int nb = swr_convert(m_pAudioConvertCtx, audio_buf, num_frames_to_read, (const uint8_t**)&p_audio_data, num_frames_to_read);

可以看到这里面的audio_buf的数组长度为1.

下面本人将重写系统音频的录制,将最终的编码格式由AV_SAMPLE_FMT_FLTP转换成AV_SAMPLE_FMT_S16,注意用windows api采取系统声音时,声音格式是AV_SAMPLE_FMT_S32,如果系统声音是AV_SAMPLE_FMT_S16,则无需进行重采样。

代码如下:
main函数所在文件FfmpegGetSystemAudio.cpp

#include <iostream>
#include "GetSystemAudio.h"int main()
{CGetSystemAudio cCGetSystemAudio;cCGetSystemAudio.SetSavePath("E:\\learn\\ffmpeg\\FfmpegTest\\x64\\Release");cCGetSystemAudio.StartCapture();Sleep(30000);cCGetSystemAudio.StopCapture();return 0;
}

GetSystemAudio.h文件内容如下:

#pragma once
#include <string>
#include <combaseapi.h>
#include <mmdeviceapi.h>
#include <audioclient.h>#ifdef    __cplusplus
extern "C"
{#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavdevice/avdevice.h"
#include "libavutil/audio_fifo.h"
#include "libavutil/avutil.h"
#include "libavutil/fifo.h"
#include "libavutil/frame.h"
#include "libavutil/imgutils.h"#include "libavfilter/avfilter.h"
#include "libavfilter/buffersink.h"
#include "libavfilter/buffersrc.h"#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")#ifdef __cplusplus
};
#endifclass CGetSystemAudio
{public:CGetSystemAudio();~CGetSystemAudio();
public:void SetSavePath(std::string strPath);int StartCapture();void StopCapture();int OpenOutPut();
private:static DWORD WINAPI AudioSystemCaptureProc(LPVOID lpParam);void AudioSystemCapture();static DWORD WINAPI AudioSystemWriteProc(LPVOID lpParam);void AudioSystemWrite();HRESULT IsFormatSupported(IAudioClient *audioClient);
private:std::string m_strRecordPath;bool m_bRecord;IAudioClient *pAudioClient = nullptr;IAudioCaptureClient *pAudioCaptureClient = nullptr;WAVEFORMATEXTENSIBLE m_formatex;HANDLE m_hAudioSystemCapture = NULL;HANDLE m_hAudioSystemWrite = NULL;AVFormatContext *m_pFormatCtx_Out = NULL;AVFormatContext  *m_pFormatCtx_AudioSystem = NULL;AVCodecContext    *m_pCodecEncodeCtx_Audio = NULL;AVCodec            *m_pCodecEncode_Audio = NULL;SwrContext *m_pAudioConvertCtx = NULL;AVAudioFifo *m_pAudioFifo = NULL;CRITICAL_SECTION m_csAudioSystemSection;
};

GetSystemAudio.cpp的内容如下:

#include "GetSystemAudio.h"
#include <iostream>
#include <fstream>
#include <thread>#define DEFAULT_SAMPLE_RATE 48000         // 默认采样率:48kHz
#define DEFAULT_BITS_PER_SAMPLE 16       // 默认位深:16bit
#define DEFAULT_CHANNELS 1               // 默认音频通道数:1
#define DEFAULT_AUDIO_PACKET_INTERVAL 10 // 默认音频包发送间隔:10msHRESULT CreateDeviceEnumerator(IMMDeviceEnumerator **enumerator)
{CoInitializeEx(nullptr, COINIT_MULTITHREADED);return CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,__uuidof(IMMDeviceEnumerator),reinterpret_cast<void **>(enumerator));
}
HRESULT CreateDevice(IMMDeviceEnumerator *enumerator, IMMDevice **device)
{EDataFlow enDataFlow = eRender;       // 表示获取扬声器的audio_endpointERole enRole = eConsole;return enumerator->GetDefaultAudioEndpoint(enDataFlow, enRole, device);
}HRESULT CreateAudioClient(IMMDevice *device, IAudioClient **audioClient)
{return device->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL,(void **)audioClient);
}HRESULT CGetSystemAudio::IsFormatSupported(IAudioClient *audioClient)
{WAVEFORMATEX *format = &m_formatex.Format;format->nSamplesPerSec = DEFAULT_SAMPLE_RATE;format->wBitsPerSample = DEFAULT_BITS_PER_SAMPLE;format->nChannels = DEFAULT_CHANNELS;WAVEFORMATEX *closestMatch = nullptr;HRESULT hr = audioClient->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, format, &closestMatch);if (hr == AUDCLNT_E_UNSUPPORTED_FORMAT) // 0x88890008{if (closestMatch != nullptr) // 如果找不到最相近的格式,closestMatch可能为nullptr{format->nSamplesPerSec = closestMatch->nSamplesPerSec;format->wBitsPerSample = closestMatch->wBitsPerSample;format->nChannels = closestMatch->nChannels;return S_OK;}}return hr;
}
HRESULT GetPreferFormat(IAudioClient *audioClient, WAVEFORMATEXTENSIBLE *formatex)
{WAVEFORMATEX *format = nullptr;HRESULT hr = audioClient->GetMixFormat(&format);if (FAILED(hr)){return hr;}formatex->Format.nSamplesPerSec = format->nSamplesPerSec;formatex->Format.wBitsPerSample = format->wBitsPerSample;formatex->Format.nChannels = format->nChannels;return hr;
}HRESULT InitAudioClient(IAudioClient *audioClient, WAVEFORMATEXTENSIBLE *formatex)
{AUDCLNT_SHAREMODE shareMode =AUDCLNT_SHAREMODE_SHARED;                      // share Audio Engine with other applicationsDWORD streamFlags = AUDCLNT_STREAMFLAGS_LOOPBACK; // loopback speakerstreamFlags |=AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM; // A channel matrixer and a sample// rate converter are insertedstreamFlags |=AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; // a sample rate converter// with better quality than// the default conversion but// with a higher performance// cost is usedREFERENCE_TIME hnsBufferDuration = 0;WAVEFORMATEX *format = &formatex->Format;format->wFormatTag = WAVE_FORMAT_EXTENSIBLE;format->nBlockAlign = (format->wBitsPerSample >> 3) * format->nChannels;format->nAvgBytesPerSec = format->nBlockAlign * format->nSamplesPerSec;format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);formatex->Samples.wValidBitsPerSample = format->wBitsPerSample;formatex->dwChannelMask =format->nChannels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO;formatex->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;return audioClient->Initialize(shareMode, streamFlags, hnsBufferDuration, 0,format, nullptr);
}HRESULT CreateAudioCaptureClient(IAudioClient *audioClient, IAudioCaptureClient **audioCaptureClient)
{HRESULT hr = audioClient->GetService(IID_PPV_ARGS(audioCaptureClient));if (FAILED(hr)){*audioCaptureClient = nullptr;}return hr;
}DWORD WINAPI CGetSystemAudio::AudioSystemCaptureProc(LPVOID lpParam)
{CGetSystemAudio *pCGetSystemAudio = (CGetSystemAudio *)lpParam;if (pCGetSystemAudio != NULL){pCGetSystemAudio->AudioSystemCapture();}return 0;
}void CGetSystemAudio::AudioSystemCapture()
{HRESULT hr = S_OK;UINT32 num_success = 0;BYTE *p_audio_data = nullptr;UINT32 num_frames_to_read = 0;DWORD dw_flag = 0;UINT32 num_frames_in_next_packet = 0;UINT32 num_loop = 0;pAudioClient->Start();int ret = 0;int AudioFrameIndex_mic = 1;while (m_bRecord){std::this_thread::sleep_for(std::chrono::milliseconds(0));while (true){hr = pAudioCaptureClient->GetNextPacketSize(&num_frames_in_next_packet);if (FAILED(hr)){throw std::exception();}if (num_frames_in_next_packet == 0){break;}hr = pAudioCaptureClient->GetBuffer(&p_audio_data, &num_frames_to_read, &dw_flag, nullptr, nullptr);if (FAILED(hr)){throw std::exception();}AVFrame *frame_mic_encode = NULL;frame_mic_encode = av_frame_alloc();frame_mic_encode->nb_samples = m_pCodecEncodeCtx_Audio->frame_size;frame_mic_encode->channel_layout = m_pCodecEncodeCtx_Audio->channel_layout;frame_mic_encode->format = m_pCodecEncodeCtx_Audio->sample_fmt;frame_mic_encode->sample_rate = m_pCodecEncodeCtx_Audio->sample_rate;av_frame_get_buffer(frame_mic_encode, 0);int iDelaySamples = 0;AVPacket pkt_out_mic = { 0 };pkt_out_mic.data = NULL;pkt_out_mic.size = 0;uint8_t *audio_buf[1] = { 0 };audio_buf[0] = (uint8_t *)frame_mic_encode->data[0];int nb = swr_convert(m_pAudioConvertCtx, audio_buf, num_frames_to_read, (const uint8_t**)&p_audio_data, num_frames_to_read);int buf_space = av_audio_fifo_space(m_pAudioFifo);if (buf_space >= frame_mic_encode->nb_samples){//AudioSectionEnterCriticalSection(&m_csAudioSystemSection);ret = av_audio_fifo_write(m_pAudioFifo, (void **)frame_mic_encode->data, num_frames_to_read);LeaveCriticalSection(&m_csAudioSystemSection);}hr = pAudioCaptureClient->ReleaseBuffer(num_frames_to_read);if (FAILED(hr)){throw std::exception();}num_loop++;}}pAudioClient->Stop();
}DWORD WINAPI CGetSystemAudio::AudioSystemWriteProc(LPVOID lpParam)
{CGetSystemAudio *pCGetSystemAudio = (CGetSystemAudio *)lpParam;if (pCGetSystemAudio != NULL){pCGetSystemAudio->AudioSystemWrite();}return 0;
}void CGetSystemAudio::AudioSystemWrite()
{int ret = 0;int AudioFrameIndex_mic = 1;AVFrame *frame_audio_system = NULL;frame_audio_system = av_frame_alloc();while (m_bRecord){if (av_audio_fifo_size(m_pAudioFifo) >=(m_pFormatCtx_Out->streams[0]->codecpar->frame_size > 0 ? m_pFormatCtx_Out->streams[0]->codecpar->frame_size : 1024)){frame_audio_system->nb_samples = m_pFormatCtx_Out->streams[0]->codecpar->frame_size > 0 ? m_pFormatCtx_Out->streams[0]->codecpar->frame_size : 1024;frame_audio_system->channel_layout = m_pFormatCtx_Out->streams[0]->codecpar->channel_layout;frame_audio_system->format = m_pFormatCtx_Out->streams[0]->codecpar->format;frame_audio_system->sample_rate = m_pFormatCtx_Out->streams[0]->codecpar->sample_rate;av_frame_get_buffer(frame_audio_system, 0);EnterCriticalSection(&m_csAudioSystemSection);int readcount = av_audio_fifo_read(m_pAudioFifo, (void **)frame_audio_system->data,(m_pFormatCtx_Out->streams[0]->codecpar->frame_size > 0 ? m_pFormatCtx_Out->streams[0]->codecpar->frame_size : 1024));LeaveCriticalSection(&m_csAudioSystemSection);AVPacket pkt_out_mic = { 0 };pkt_out_mic.data = NULL;pkt_out_mic.size = 0;ret = avcodec_send_frame(m_pCodecEncodeCtx_Audio, frame_audio_system);ret = avcodec_receive_packet(m_pCodecEncodeCtx_Audio, &pkt_out_mic);pkt_out_mic.stream_index = 0;pkt_out_mic.pts = AudioFrameIndex_mic * readcount;pkt_out_mic.dts = AudioFrameIndex_mic * readcount;pkt_out_mic.duration = readcount;av_write_frame(m_pFormatCtx_Out, &pkt_out_mic);av_packet_unref(&pkt_out_mic);AudioFrameIndex_mic++;}else{Sleep(1);if (!m_bRecord){break;}}}Sleep(100);av_frame_free(&frame_audio_system);av_write_trailer(m_pFormatCtx_Out);avio_close(m_pFormatCtx_Out->pb);
}CGetSystemAudio::CGetSystemAudio()
{m_bRecord = false;m_hAudioSystemCapture = NULL;InitializeCriticalSection(&m_csAudioSystemSection);
}CGetSystemAudio::~CGetSystemAudio()
{DeleteCriticalSection(&m_csAudioSystemSection);
}int CGetSystemAudio::OpenOutPut()
{std::string strFileName = m_strRecordPath;int iRet = -1;AVStream *pAudioStream = NULL;do{std::string strFileName = m_strRecordPath;strFileName += "system_audio";strFileName += ".mp4";const char *outFileName = strFileName.c_str();avformat_alloc_output_context2(&m_pFormatCtx_Out, NULL, NULL, outFileName);{pAudioStream = avformat_new_stream(m_pFormatCtx_Out, NULL);//m_pCodecEncode_Audio = (AVCodec *)avcodec_find_encoder(m_pFormatCtx_Out->oformat->audio_codec);m_pCodecEncode_Audio = (AVCodec *)avcodec_find_encoder_by_name("libfdk_aac");m_pCodecEncodeCtx_Audio = avcodec_alloc_context3(m_pCodecEncode_Audio);if (!m_pCodecEncodeCtx_Audio){break;}//pCodecEncodeCtx_Audio->codec_id = pFormatCtx_Out->oformat->audio_codec;//m_pCodecEncodeCtx_Audio->sample_fmt = m_pCodecEncode_Audio->sample_fmts ? m_pCodecEncode_Audio->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;int i = 0;enum AVSampleFormat sampleFmt;sampleFmt = m_pCodecEncode_Audio->sample_fmts[i];while (sampleFmt != AV_SAMPLE_FMT_NONE){i++;sampleFmt = m_pCodecEncode_Audio->sample_fmts[i];}m_pCodecEncodeCtx_Audio->sample_fmt = AV_SAMPLE_FMT_S16;m_pCodecEncodeCtx_Audio->bit_rate = 64000;m_pCodecEncodeCtx_Audio->sample_rate = 48000;m_pCodecEncodeCtx_Audio->channel_layout = AV_CH_LAYOUT_STEREO;m_pCodecEncodeCtx_Audio->channels = av_get_channel_layout_nb_channels(m_pCodecEncodeCtx_Audio->channel_layout);AVRational timeBase;timeBase.den = m_pCodecEncodeCtx_Audio->sample_rate;timeBase.num = 1;pAudioStream->time_base = timeBase;if (avcodec_open2(m_pCodecEncodeCtx_Audio, m_pCodecEncode_Audio, 0) < 0){//编码器打开失败,退出程序break;}}if (!(m_pFormatCtx_Out->oformat->flags & AVFMT_NOFILE)){if (avio_open(&m_pFormatCtx_Out->pb, outFileName, AVIO_FLAG_WRITE) < 0){break;}}avcodec_parameters_from_context(pAudioStream->codecpar, m_pCodecEncodeCtx_Audio);if (avformat_write_header(m_pFormatCtx_Out, NULL) < 0){break;}iRet = 0;} while (0);if (iRet != 0){if (m_pCodecEncodeCtx_Audio != NULL){avcodec_free_context(&m_pCodecEncodeCtx_Audio);m_pCodecEncodeCtx_Audio = NULL;}if (m_pFormatCtx_Out != NULL){avformat_free_context(m_pFormatCtx_Out);m_pFormatCtx_Out = NULL;}}return iRet;
}void CGetSystemAudio::SetSavePath(std::string strPath)
{m_strRecordPath = strPath;if (!m_strRecordPath.empty()){if (m_strRecordPath[m_strRecordPath.length() - 1] != '\\'){m_strRecordPath = m_strRecordPath + "\\";}}
}int CGetSystemAudio::StartCapture()
{int iRet = -1;do {iRet = OpenOutPut();if (iRet < 0){break;}IMMDeviceEnumerator *pDeviceEnumerator = nullptr;IMMDevice *pDevice = nullptr;std::unique_ptr<std::thread> capture_thread = nullptr;std::string input_str;HRESULT hr;hr = CreateDeviceEnumerator(&pDeviceEnumerator);if (FAILED(hr)){break;}hr = CreateDevice(pDeviceEnumerator, &pDevice);if (FAILED(hr)){break;}hr = CreateAudioClient(pDevice, &pAudioClient);if (FAILED(hr)){break;}hr = IsFormatSupported(pAudioClient);if (FAILED(hr)){hr = GetPreferFormat(pAudioClient, &m_formatex);if (FAILED(hr)){break;}}hr = InitAudioClient(pAudioClient, &m_formatex);if (FAILED(hr)){break;}hr = CreateAudioCaptureClient(pAudioClient, &pAudioCaptureClient);if (FAILED(hr)){break;}m_pAudioConvertCtx = swr_alloc();av_opt_set_channel_layout(m_pAudioConvertCtx, "in_channel_layout", AV_CH_LAYOUT_STEREO, 0);av_opt_set_channel_layout(m_pAudioConvertCtx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);av_opt_set_int(m_pAudioConvertCtx, "in_sample_rate", m_formatex.Format.nSamplesPerSec, 0);av_opt_set_int(m_pAudioConvertCtx, "out_sample_rate", 48000, 0);av_opt_set_sample_fmt(m_pAudioConvertCtx, "in_sample_fmt", AV_SAMPLE_FMT_S32, 0);av_opt_set_sample_fmt(m_pAudioConvertCtx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);iRet = swr_init(m_pAudioConvertCtx);if (NULL == m_pAudioFifo){m_pAudioFifo = av_audio_fifo_alloc((AVSampleFormat)m_pFormatCtx_Out->streams[0]->codecpar->format,m_pFormatCtx_Out->streams[0]->codecpar->channels, 3000 * 1024);}m_bRecord = true;m_hAudioSystemCapture = CreateThread(NULL, 0, AudioSystemCaptureProc, this, 0, NULL);m_hAudioSystemWrite = CreateThread(NULL, 0, AudioSystemWriteProc, this, 0, NULL);iRet = 0;} while (0);return 0;
}void CGetSystemAudio::StopCapture()
{m_bRecord = false;Sleep(1000);WaitForSingleObject(m_hAudioSystemCapture, INFINITE);CloseHandle(m_hAudioSystemCapture);m_hAudioSystemCapture = NULL;
}

音频编码器为packed(非planar)格式时的说明相关推荐

  1. 成功解决pillow模块内生成的非UTF-8格式(比如label中有汉字时)

    成功解决pillow模块内生成的非UTF-8格式(比如label中有汉字时) 目录 解决问题 解决方法 解决问题 解决pillow模块内生成的非UTF-8格式(比如label中有汉字时),需要进行格式 ...

  2. 火山引擎 RTC 自研音频编码器 NICO 实践之路

    本文作者:张德军 1. 前言 随着互联网技术的不断发展,越来越多的人开始尝试使用或者依赖实时音视频产品解决团队沟通与协作问题.在通话过程中,我们时常会遇到因为网络波动(如拥塞.丢包.延时和抖动等)而导 ...

  3. 两个mp3文件合成 php,两个音频合成一个 音频合成软件/音频视频合成软件合并不同格式为一个音频文件...

    怎么将两个音频合成一个音频文件,嗯~ o(* ̄▽ ̄*)o ,又是一个老生常谈的话题,但既然是提到了自然是再给大伙演示一下,那就使用一个比较简单的音频合成软件/音频视频合成软件合并不同格式为一个音频文件 ...

  4. 图像存储策略:Packed与Planar

    作者:满嘴跑火车的小土匪 Packed与Planar 在计算机图形学中,Packed和Packed是两种主要的像素数据存储方式. Packed:每个像素在内存中是连续存储的.如果每个像素有16bit, ...

  5. 最简单的基于FFMPEG的音频编码器(PCM编码为AAC)

    本文介绍一个最简单的基于FFMPEG的音频编码器.该编码器实现了PCM音频采样数据编码为AAC的压缩编码数据.编码器代码十分简单,但是每一行代码都很重要.通过看本编码器的源代码,可以了解FFMPEG音 ...

  6. CAD图纸转换TIFF格式时修改背景颜色

    接触CAD相关工作的小伙伴,常常会对CAD图纸进行格式转换,CAD图纸转换图片格式就是较为常见的,这其中就有CAD图纸转换成TIFF图片格式.而CAD图纸转换TIFF图片格式的时候,可能需要修改背景颜 ...

  7. 音频文件如何转成mp3格式

    当提到音频文件格式时,大家往往会想到最为流行和广泛使用的mp3格式.mp3是一种广受欢迎的音频格式,因为各种音频格式自身特点的原因,所以将其他格式的音频文件转换成mp3是非常普遍的需求.就比如在我们日 ...

  8. WAVE音频文件格式及其64位扩展格式的简要介绍

    正文 关于 WAVE 文件格式,网上有不少介绍,但关于WAVE 64位扩展格式的介绍却是几乎没有. 所以本文的目的是简要介绍标准的 WAVE 格式,以及两种主要的扩展格式. 文中所有代码都用C语言来描 ...

  9. 三招让你学会,其他音频文件怎么转换成mp3格式

    音频文件转换为mp3格式是非常常见的操作,因为mp3是一种广泛使用的音频格式,支持多种设备和应用程序.本文将介绍三种不同的方法,让你知道音频文件怎么转换成mp3格式,帮助您将音频文件转换为mp3格式. ...

最新文章

  1. android 结束if循环_Android Handler 消息循环机制
  2. 华为手机怎么看图片属性_华为手机音量小怎么办
  3. ai包装插件_找AI插件很费劲,一次给你66款AI插件合集!每一款都是设计师常用...
  4. ipv6的127位掩码如何表示_子网掩码
  5. PDH光端机常见故障问题解决方法
  6. mysql中对象标识符的命名规则,标准规范数据库命名规范.doc
  7. springboot转发http请求_Spring Boot2 系列教程(八)Spring Boot 中配置 Https
  8. [深入React] 8.refs
  9. SPSS基础操作详解---系统环境设置篇
  10. android fastboot模式下载以及出现的问题
  11. 论文阅读 -- unsupervised triplet hashing for fast image retrieval笔记
  12. android studio夜间模式,android studio怎样实现夜间模式
  13. 13 个非常有用的 Python 代码片段,建议收藏
  14. Camera 的3A
  15. 《算法图解》读书笔记
  16. 毕设专题1 — 开始准备结束的任务
  17. GITHUB实用有趣工具推荐
  18. 收楼了心情忐忑不安,该花钱请验房师来验房吗?找一个验房师需要多少钱,验房标准价格是多少,验房师现场验收出二百多个问题值不值
  19. linux更改patrol密码,Linux常用的文件管理命令及用户管理命令
  20. 珊瑚虫版QQ被判侵犯腾讯著作权 可能停止更新

热门文章

  1. JavaScript进阶必会的手写功能
  2. 一个好锅,等于拥有一个家庭的灵魂~
  3. 怎么删除计算机c盘应用程序,怎么删除流氓软件?
  4. 【全栈开发】精通 MEAN: MEAN 堆栈
  5. 华科计算机层次结构图,xchap-2-2_华中科技大学计算机学院:2007本科计算机系统结构(刘芳)_ppt_大学课件预览_高等教育资讯网...
  6. win10系统崩溃、重装后 Hyper-V 导入虚拟机的使用
  7. C# 打印机使用PrintDialog、PrintTicket、PrintQueue
  8. 网站负载均衡与容灾备份方案
  9. 国际安全标准ISO 15408简介
  10. 金士顿服务器内存条型号解读,金士顿骇内存新版型号编码规则是什么?