【FFmpeg(2016)】SwrContext 변환 PCM 오디 오 비트
【FFmpeg(2016)】PCM 인 코딩 AAC
[FFmpeg(2016)]SwrContext 재 샘플링 구조 체
【머리말】
이틀 동안 오디 오 인 코딩 을 하고 있 지만 FFmpeg 인 코딩 라 이브 러 리 avcodec 는 20m 정도 크기 때문에 다른 라 이브 러 리 로 인 코딩 하기 로 했 습 니 다.인터넷 에서 faac 의 부피 가 작고 직접 디 코딩 을 하 는 것 을 발견 하여 faac 라 이브 러 리 를 인 코딩 모듈 로 사용 하기 로 결정 했다.
그러나 faac 의 원본 코드 에서 다음 과 같은 형식의 PCM 인 코딩 만 지원 합 니 다.
PCM Sample Input Format0 FAAC_INPUT_NULL invalid, signifies a misconfigured config1 FAAC_INPUT_16BIT native endian 16bit2 FAAC_INPUT_24BIT native endian 24bit in 24 bits (not implemented)3 FAAC_INPUT_32BIT native endian 24bit in 32 bits (DEFAULT)4 FAAC_INPUT_FLOAT 32bit floating point
내 가 인 코딩 하고 자 하 는 PCM 은 32bit float 인 데 faac 인 코딩 을 사용 할 때 항상 오류 가 발생 하여 ffmpeg 의 인 코딩 라 이브 러 리 를 사용 하여 자릿수 변환 을 하기 로 결정 했다.
[FFmpeg 및 오디 오 관련 개념]
4
enum AVSampleFormat {
AV_SAMPLE_FMT_NONE = -1,
AV_SAMPLE_FMT_U8, ///< unsigned 8 bits
AV_SAMPLE_FMT_S16, ///< signed 16 bits
AV_SAMPLE_FMT_S32, ///< signed 32 bits
AV_SAMPLE_FMT_FLT, ///< float
AV_SAMPLE_FMT_DBL, ///< double
AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP, ///< float, planar
AV_SAMPLE_FMT_DBLP, ///< double, planar
AV_SAMPLE_FMT_S64, ///< signed 64 bits
AV_SAMPLE_FMT_S64P, ///< signed 64 bits, planar
AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically
};
이것 은 ffmpeg 가 나열 한 오디 오 형식 으로 P 를 가 진 것 은 평면 데이터 임 을 나타 낸다.오디 오 저장 형식의 두 가지 개념 을 소개 합 니 다. 스테레오 저장 소 와 더 블 사 운 드 채널 이 교차 하 다.
교차 스테레오 저장,즉 두 채널 의 오디 오 저장 형식 은 L(하나의 샘플링 포인트)RLRLRLR 입 니 다.
더 블 사 운 드 채널,즉 L(하나의 샘플링 포인트)LLLLLLLLLLRRRRRRRRRRRRRRRLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
지금까지 FFmpeg API 에서 나 는 sample 만 있 는 것 을 발견 했다.fmt 는 AVSAMPLE_FMT_FLTP 의 오디 오 인 코더 가 열 릴 수 있 습 니 다.즉,인 코딩 형식 만 AV 로 지원 합 니 다.SAMPLE_FMT_FLTP 의 PCM 오디 오.
다른 형식의 PCM 데이터 인 코딩 은 지원 되 지 않 지만 모든 형식의 상호 변환 을 지원 하기 때문에 어떤 형식의 오디 오 를 가지 고 있 든 SwrContext 를 사용 하여 AV 로 변환 하면 됩 니 다.SAMPLE_FMT_FLTP,FFmpeg 인 코딩 을 사용 할 수 있 습 니 다.
【코드】
원본 PCM 데이터:
sample_rate = 48000
channels = 2
sample_fmt = AV_SAMPLE_FMT_FLT
대상 PCM 데이터:
sample_rate = 48000
channels = 2
sample_fmt = AV_SAMPLE_FMT_U8
원본 데이터 와 대상 데 이 터 는 모두 교차 스테레오 저장 소 입 니 다.(주의:FFmpeg PCM 형식 매 거 진 에 P 가 있 는 접 두 사 는 이 매개 변수 로 초기 화 된 인 코더 임 을 표시 합 니 다.원본 데 이 터 는 교차 스테레오 저장 소 여야 합 니 다)
SwrContext *swr_ctx = NULL;
FILE *fp_in = NULL;
fp_in = fopen("in.pcm", "rb");
FILE *outpcm = NULL;
outpcm = fopen("out.pcm", "wb");
uint8_t **convert_data;
uint8_t* frame_buf;
int framenum = 100000;
int nb_samples = 1024;
int channels = 2;
int samplerate = 48000;
swr_ctx = swr_alloc_set_opts(
NULL,
AV_CH_LAYOUT_STEREO,
AV_SAMPLE_FMT_U8,
samplerate,
AV_CH_LAYOUT_STEREO,
AV_SAMPLE_FMT_FLT,
samplerate,
0, NULL);
swr_init(swr_ctx);
/* , */
convert_data = (uint8_t**)calloc(
channels,
sizeof(*convert_data));
int sizes = av_samples_alloc(
convert_data, NULL,
channels, nb_samples,
AV_SAMPLE_FMT_U8, 0);
/* */
size = av_samples_get_buffer_size(NULL, channels, nb_samples, AV_SAMPLE_FMT_FLT, 0);
frame_buf = (uint8_t *)av_malloc(size);
ret = avcodec_fill_audio_frame(pFrame, channels, AV_SAMPLE_FMT_FLT, (const uint8_t*)frame_buf, size, 0);
if (ret < 0)
{
qDebug() << "avcodec_fill_audio_frame error ";
return 0;
}
for (i = 0; i < framenum; i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
//Read raw data
if (fread(frame_buf, 1, size, fp_in) <= 0) {
printf("Failed to read raw data!
");
return -1;
}
else if (feof(fp_in)) {
break;
}
/* , ( )*/
swr_convert(swr_ctx, convert_data, nb_samples ,
(const uint8_t**)pFrame->data, nb_samples );
fwrite(convert_data[0], nb_samples * channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_U8), 1, outpcm);
}
[코드 해석]
FFmpeg 처리 중 교차 스테레오 저장 및 2 성 모 노 채널 에서 구조 체 의 저장 방식 이 약간 다르다.
AVSAMPLE_FMT_FLT 등급 AVSAMPLE_FMT_U8,그러면 대상 데이터 의 메모리 공간 은 원본 데이터 의 1/4 만 필요 합 니 다.
다음은 avsample_alloc 무슨 일이 야?
int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels,
int nb_samples, enum AVSampleFormat sample_fmt, int align)
{
uint8_t *buf;
//
int size = av_samples_get_buffer_size(NULL, nb_channels, nb_samples,
sample_fmt, align);
if (size < 0)
return size;
buf = av_malloc(size);
if (!buf)
return AVERROR(ENOMEM);
size = av_samples_fill_arrays(audio_data, linesize, buf, nb_channels,
nb_samples, sample_fmt, align);
if (size < 0) {
av_free(buf);
return size;
}
// ...
return size;
}
int av_samples_fill_arrays(uint8_t **audio_data, int *linesize,
const uint8_t *buf, int nb_channels, int nb_samples,
enum AVSampleFormat sample_fmt, int align)
{
int ch, planar, buf_size, line_size;
planar = av_sample_fmt_is_planar(sample_fmt);
buf_size = av_samples_get_buffer_size(&line_size, nb_channels, nb_samples,
sample_fmt, align);
if (buf_size < 0)
return buf_size;
audio_data[0] = (uint8_t *)buf; //
for (ch = 1; planar && ch < nb_channels; ch++)
audio_data[ch] = audio_data[ch-1] + line_size;
if (linesize)
*linesize = line_size;
return buf_size;
}
이상 호출 avsamples_get_buffer_size 의 첫 번 째 매개 변 수 는 모든 채널 이 차지 하 는 바이트 수 를 되 돌려 줍 니 다.
이 PCM 이 평면 데이터 에 속한다 면 메모 리 는 모든 채널 에 평균 적 으로 분 배 됩 니 다.이때 audio 와 같 습 니 다.data[0] audio_data[1]....;
비 평면 데이터 에 대해 서 는 첫 번 째 요 소 를 audiodata[0]포인터
int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples,
enum AVSampleFormat sample_fmt, int align)
{
int line_size;
int sample_size = av_get_bytes_per_sample(sample_fmt);
int planar = av_sample_fmt_is_planar(sample_fmt);
/* validate parameter ranges */
if (!sample_size || nb_samples <= 0 || nb_channels <= 0)
return AVERROR(EINVAL);
/* auto-select alignment if not specified */
if (!align) {
if (nb_samples > INT_MAX - 31)
return AVERROR(EINVAL);
align = 1;
nb_samples = FFALIGN(nb_samples, 32);
}
/* check for integer overflow */
if (nb_channels > INT_MAX / align ||
(int64_t)nb_channels * nb_samples > (INT_MAX - (align * nb_channels)) / sample_size)
return AVERROR(EINVAL);
line_size = planar ? FFALIGN(nb_samples * sample_size, align) : //
FFALIGN(nb_samples * sample_size * nb_channels, align);
if (linesize)
*linesize = line_size;
return planar ? line_size * nb_channels : line_size;
}
왜냐하면 저희 가 AV 를 사용 하 거 든 요.SAMPLES_FMT_U8,그래서 결과 데 이 터 를 처리 할 때 convertdata[0]포인터.
avcodec_fill_audio_frame 호출 동 리 는 AV 이기 때 문 입 니 다.SAMPLES_FMT_FLT 비평 면 형식,pFrame->data[0]모든 데이터(좌우 채널)가리 키 기
사실 그들의 메모리 공간 은 똑 같이 크다.
비 planr:data[0]->[8192 바이트]
planr:data[0]->[4096 바이트]data[1]->[4096 바이트]
[평면 과 비 평면 형식의 상호 전환]
평면 데이터 에 몇 개의 채널 이 있 습 니까?그러면 data 2 차원 포인터 에 몇 개의 요소 가 메모 리 를 가리 키 고 있 습 니 다.예 를 들 어 3 개의 채널 이 라면.
그러면 AVFrame 의 data[0]data[1]data[2]는 각각 응답 위 치 를 가리 키 며 모든 채널 에 메모 리 를 제공 합 니 다(참고 로 모든 채널 의 데이터 크기 는 같 습 니 다).
다음은 FFmpeg 이 지원 하 는 layot 입 니 다.
/**
* @}
* @defgroup channel_mask_c Audio channel layouts
* @{
* */
#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER)
#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT)
#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY)
#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER)
#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER)
#define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY)
#define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER)
#define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY)
#define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT)
#define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
#define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT)
#define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY)
#define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
#define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY)
#define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER)
#define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
#define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER)
#define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER)
#define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER)
#define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY)
#define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
#define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
#define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT)
#define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
#define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER)
#define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT)
#define AV_CH_LAYOUT_HEXADECAGONAL (AV_CH_LAYOUT_OCTAGONAL|AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT)
#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT)
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
09.문자 / 메모리영역//메모리 영역 스택 데이터 ROM(코드) //읽기전용메모리 문자 char(1),wchar(2) 바이트 . char c = 'a'; wchar_t wc = L'a';...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.