test-resample.cpp revision 9aec8c3f7f72cd36a8e3d7aafc1149f50514087a
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "AudioResampler.h"
18#include <media/AudioBufferProvider.h>
19#include <unistd.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <fcntl.h>
23#include <string.h>
24#include <sys/mman.h>
25#include <sys/stat.h>
26#include <errno.h>
27#include <time.h>
28
29using namespace android;
30
31struct HeaderWav {
32    HeaderWav(size_t size, int nc, int sr, int bits) {
33        strncpy(RIFF, "RIFF", 4);
34        chunkSize = size + sizeof(HeaderWav);
35        strncpy(WAVE, "WAVE", 4);
36        strncpy(fmt,  "fmt ", 4);
37        fmtSize = 16;
38        audioFormat = 1;
39        numChannels = nc;
40        samplesRate = sr;
41        byteRate = sr * numChannels * (bits/8);
42        align = nc*(bits/8);
43        bitsPerSample = bits;
44        strncpy(data, "data", 4);
45        dataSize = size;
46    }
47
48    char RIFF[4];           // RIFF
49    uint32_t chunkSize;     // File size
50    char WAVE[4];        // WAVE
51    char fmt[4];            // fmt\0
52    uint32_t fmtSize;       // fmt size
53    uint16_t audioFormat;   // 1=PCM
54    uint16_t numChannels;   // num channels
55    uint32_t samplesRate;   // sample rate in hz
56    uint32_t byteRate;      // Bps
57    uint16_t align;         // 2=16-bit mono, 4=16-bit stereo
58    uint16_t bitsPerSample; // bits per sample
59    char data[4];           // "data"
60    uint32_t dataSize;      // size
61};
62
63static int usage(const char* name) {
64    fprintf(stderr,"Usage: %s [-p] [-h] [-q <dq|lq|mq|hq|vhq>] [-i <input-sample-rate>] [-o <output-sample-rate>] <input-file> <output-file>\n", name);
65    fprintf(stderr,"-p              - enable profiling\n");
66    fprintf(stderr,"-h              - create wav file\n");
67    fprintf(stderr,"-q              - resampler quality\n");
68    fprintf(stderr,"                  dq  : default quality\n");
69    fprintf(stderr,"                  lq  : low quality\n");
70    fprintf(stderr,"                  mq  : medium quality\n");
71    fprintf(stderr,"                  hq  : high quality\n");
72    fprintf(stderr,"                  vhq : very high quality\n");
73    fprintf(stderr,"-i              - input file sample rate\n");
74    fprintf(stderr,"-o              - output file sample rate\n");
75    return -1;
76}
77
78int main(int argc, char* argv[]) {
79
80    bool profiling = false;
81    bool writeHeader = false;
82    int input_freq = 0;
83    int output_freq = 0;
84    AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY;
85
86    int ch;
87    while ((ch = getopt(argc, argv, "phq:i:o:")) != -1) {
88        switch (ch) {
89        case 'p':
90            profiling = true;
91            break;
92        case 'h':
93            writeHeader = true;
94            break;
95        case 'q':
96            if (!strcmp(optarg, "dq"))
97                quality = AudioResampler::DEFAULT_QUALITY;
98            else if (!strcmp(optarg, "lq"))
99                quality = AudioResampler::LOW_QUALITY;
100            else if (!strcmp(optarg, "mq"))
101                quality = AudioResampler::MED_QUALITY;
102            else if (!strcmp(optarg, "hq"))
103                quality = AudioResampler::HIGH_QUALITY;
104            else if (!strcmp(optarg, "vhq"))
105                quality = AudioResampler::VERY_HIGH_QUALITY;
106            else {
107                usage(argv[0]);
108                return -1;
109            }
110            break;
111        case 'i':
112            input_freq = atoi(optarg);
113            break;
114        case 'o':
115            output_freq = atoi(optarg);
116            break;
117        case '?':
118        default:
119            usage(argv[0]);
120            return -1;
121        }
122    }
123    argc -= optind;
124
125    if (argc != 2) {
126        usage(argv[0]);
127        return -1;
128    }
129
130    argv += optind;
131
132    // ----------------------------------------------------------
133
134    struct stat st;
135    if (stat(argv[0], &st) < 0) {
136        fprintf(stderr, "stat: %s\n", strerror(errno));
137        return -1;
138    }
139
140    int input_fd = open(argv[0], O_RDONLY);
141    if (input_fd < 0) {
142        fprintf(stderr, "open: %s\n", strerror(errno));
143        return -1;
144    }
145
146    size_t input_size = st.st_size;
147    void* input_vaddr = mmap(0, input_size, PROT_READ, MAP_PRIVATE, input_fd,
148            0);
149    if (input_vaddr == MAP_FAILED ) {
150        fprintf(stderr, "mmap: %s\n", strerror(errno));
151        return -1;
152    }
153
154//    printf("input  sample rate: %d Hz\n", input_freq);
155//    printf("output sample rate: %d Hz\n", output_freq);
156//    printf("input mmap: %p, size=%u\n", input_vaddr, input_size);
157
158    // ----------------------------------------------------------
159
160    class Provider: public AudioBufferProvider {
161        int16_t* mAddr;
162        size_t mNumFrames;
163    public:
164        Provider(const void* addr, size_t size) {
165            mAddr = (int16_t*) addr;
166            mNumFrames = size / sizeof(int16_t);
167        }
168        virtual status_t getNextBuffer(Buffer* buffer,
169                int64_t pts = kInvalidPTS) {
170            buffer->frameCount = mNumFrames;
171            buffer->i16 = mAddr;
172            return NO_ERROR;
173        }
174        virtual void releaseBuffer(Buffer* buffer) {
175        }
176    } provider(input_vaddr, input_size);
177
178    size_t output_size = 2 * 2 * ((int64_t) input_size * output_freq)
179            / input_freq;
180    output_size &= ~7; // always stereo, 32-bits
181
182    void* output_vaddr = malloc(output_size);
183    memset(output_vaddr, 0, output_size);
184
185    AudioResampler* resampler = AudioResampler::create(16, 1, output_freq,
186            quality);
187
188    size_t out_frames = output_size/8;
189    resampler->setSampleRate(input_freq);
190    resampler->setVolume(0x1000, 0x1000);
191    resampler->resample((int*) output_vaddr, out_frames, &provider);
192
193    if (profiling) {
194        memset(output_vaddr, 0, output_size);
195        timespec start, end;
196        clock_gettime(CLOCK_MONOTONIC_HR, &start);
197        resampler->resample((int*) output_vaddr, out_frames, &provider);
198        clock_gettime(CLOCK_MONOTONIC_HR, &end);
199        int64_t start_ns = start.tv_sec * 1000000000LL + start.tv_nsec;
200        int64_t end_ns = end.tv_sec * 1000000000LL + end.tv_nsec;
201        int64_t time = end_ns - start_ns;
202        printf("%f Mspl/s\n", out_frames/(time/1e9)/1e6);
203    }
204
205    // down-mix (we just truncate and keep the left channel)
206    int32_t* out = (int32_t*) output_vaddr;
207    int16_t* convert = (int16_t*) malloc(out_frames * sizeof(int16_t));
208    for (size_t i = 0; i < out_frames; i++) {
209        int32_t s = out[i * 2] >> 12;
210        if (s > 32767)       s =  32767;
211        else if (s < -32768) s = -32768;
212        convert[i] = int16_t(s);
213    }
214
215    // write output to disk
216    int output_fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC,
217            S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
218    if (output_fd < 0) {
219        fprintf(stderr, "open: %s\n", strerror(errno));
220        return -1;
221    }
222
223    if (writeHeader) {
224        HeaderWav wav(out_frames*sizeof(int16_t), 1, output_freq, 16);
225        write(output_fd, &wav, sizeof(wav));
226    }
227
228    write(output_fd, convert, out_frames * sizeof(int16_t));
229    close(output_fd);
230
231    return 0;
232}
233