| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008 |
- // Recorder.cpp : Defines the entry point for the console application.
- //
- #include <exception>
- #include <iostream>
- extern "C" {
- #include "common.h"
- }
- #include "headers_ffmpeg.h"
- void capture_screen()
- {
- try {
- ffmpeg_register_all();
- ffmpeg_register_devices();
- AVFormatContext *pFormatCtx = avformat_alloc_context();
- const AVInputFormat *ifmt = av_find_input_format("gdigrab");
- avformat_open_input(&pFormatCtx, "desktop", ifmt, NULL);
- if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
- throw std::exception("could not find stream information");
- }
- int videoIndex = -1;
- for (int i = 0; i < pFormatCtx->nb_streams; i++) {
- if (ffmpeg_get_codec_type(pFormatCtx->streams[i]) == AVMEDIA_TYPE_VIDEO) {
- videoIndex = i;
- break;
- }
- }
- if (videoIndex == -1)
- throw std::exception("could not find a video stream");
- AVCodecContext *pDecoderCtx = ffmpeg_get_codec_context(pFormatCtx->streams[videoIndex]);
- //init decoder
- AVCodec *pDecoder = avcodec_find_decoder(pDecoderCtx->codec_id);
- if (pDecoder == NULL)
- throw std::exception("could not find codec");
- if (avcodec_open2(pDecoderCtx, pDecoder, NULL) != 0) {
- throw std::exception("open codec ffailed");
- }
- //init transfer and buffer
- AVFrame *pFrameRGB, *pFrameYUV;
- pFrameRGB = av_frame_alloc();
- pFrameYUV = av_frame_alloc();
- uint8_t *out_buffer = (uint8_t *) av_malloc(
- avpicture_get_size(AV_PIX_FMT_YUV420P, pDecoderCtx->width, pDecoderCtx->height));
- avpicture_fill((AVPicture *) pFrameYUV,
- out_buffer,
- AV_PIX_FMT_YUV420P,
- pDecoderCtx->width,
- pDecoderCtx->height);
- int ret, gotPic = 0;
- AVPacket *packet = (AVPacket *) av_malloc(sizeof(AVPacket));
- struct SwsContext *imgConvertCtx = NULL;
- imgConvertCtx = sws_getContext(pDecoderCtx->width,
- pDecoderCtx->height,
- pDecoderCtx->pix_fmt,
- pDecoderCtx->width,
- pDecoderCtx->height,
- AV_PIX_FMT_YUV420P,
- SWS_BICUBIC,
- NULL,
- NULL,
- NULL);
- //init encoder
- AVCodec *pEncoder = avcodec_find_encoder(AV_CODEC_ID_H264);
- if (pEncoder == NULL)
- throw std::exception("could not find encoder");
- AVCodecContext *pEncoderCtx = avcodec_alloc_context3(pEncoder);
- if (pEncoderCtx == NULL)
- throw std::exception("could not alloc context for encoder");
- pEncoderCtx->codec_id = AV_CODEC_ID_H264;
- pEncoderCtx->codec_type = AVMEDIA_TYPE_VIDEO;
- pEncoderCtx->pix_fmt = AV_PIX_FMT_YUV420P;
- pEncoderCtx->width = pDecoderCtx->width;
- pEncoderCtx->height = pDecoderCtx->height;
- pEncoderCtx->time_base.num = 1;
- pEncoderCtx->time_base.den = 20; //֡��(��һ���Ӷ�����ͼƬ)
- pEncoderCtx->bit_rate = 4000000; //������(���������С���Ըı�������Ƶ������)
- pEncoderCtx->gop_size = 12;
- if (pEncoderCtx->flags & AVFMT_GLOBALHEADER)
- pEncoderCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
- AVDictionary *param = 0;
- av_dict_set(¶m, "preset", "superfast", 0);
- av_dict_set(¶m, "tune", "zerolatency", 0);
- pEncoder = avcodec_find_encoder(pEncoderCtx->codec_id);
- if (pEncoder == NULL)
- throw std::exception("could not find encoder by context");
- if (avcodec_open2(pEncoderCtx, pEncoder, ¶m) != 0)
- throw std::exception("open encoder failed");
- AVFrame *pFrame264 = av_frame_alloc();
- int frame264Size = avpicture_get_size(pEncoderCtx->pix_fmt,
- pEncoderCtx->width,
- pEncoderCtx->height);
- uint8_t *frame264Buf = (uint8_t *) av_malloc(frame264Size);
- avpicture_fill((AVPicture *) pFrame264,
- frame264Buf,
- pEncoderCtx->pix_fmt,
- pEncoderCtx->width,
- pEncoderCtx->height);
- AVPacket pkt264;
- av_new_packet(&pkt264, frame264Size);
- int Y_size = pEncoderCtx->width * pEncoderCtx->height;
- for (;;) {
- if (av_read_frame(pFormatCtx, packet) < 0) {
- break;
- }
- if (packet->stream_index == videoIndex) {
- ret = avcodec_decode_video2(pDecoderCtx, pFrameRGB, &gotPic, packet);
- if (ret < 0) {
- throw std::exception("decode error");
- }
- //trans rgb to yuv420 in out_buffer
- if (gotPic) {
- sws_scale(imgConvertCtx,
- (const uint8_t *const *) pFrameRGB->data,
- pFrameRGB->linesize,
- 0,
- pDecoderCtx->height,
- pFrameYUV->data,
- pFrameYUV->linesize);
- gotPic = 0;
- pFrame264->data[0] = out_buffer; //Y
- pFrame264->data[1] = out_buffer + Y_size; //U
- pFrame264->data[2] = out_buffer + Y_size * 5 / 4; //V
- ret = avcodec_encode_video2(pEncoderCtx, &pkt264, pFrame264, &gotPic);
- if (gotPic == 1) {
- printf("264 packet:%d\r\n", pkt264.size);
- static FILE *fp = fopen("a.264", "wb+");
- fwrite(pkt264.data, 1, pkt264.size, fp);
- av_free_packet(&pkt264);
- }
- }
- _sleep(50);
- }
- av_free_packet(packet);
- } //for(;;��
- av_free(pFrameYUV);
- avcodec_close(pDecoderCtx);
- avformat_close_input(&pFormatCtx);
- } catch (std::exception ex) {
- printf("%s\r\n", ex.what());
- }
- }
- #include <AudioClient.h>
- #include <AudioPolicy.h>
- #include <MMDeviceAPI.h>
- #define REFTIMES_PER_SEC 10000000
- #define REFTIMES_PER_MILLISEC 10000
- #define EXIT_ON_ERROR(hres) \
- if (FAILED(hres)) { \
- goto Exit; \
- }
- #define SAFE_RELEASE(punk) \
- if ((punk) != NULL) { \
- (punk)->Release(); \
- (punk) = NULL; \
- }
- const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
- const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
- const IID IID_IAudioClient = __uuidof(IAudioClient);
- const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
- #define MoveMemory RtlMoveMemory
- #define CopyMemory RtlCopyMemory
- #define FillMemory RtlFillMemory
- #define ZeroMemory RtlZeroMemory
- #define min(a, b) (((a) < (b)) ? (a) : (b))
- //
- // WAV file writer.
- //
- // This is a VERY simple .WAV file writer.
- //
- //
- // A wave file consists of:
- //
- // RIFF header: 8 bytes consisting of the signature "RIFF" followed by a 4 byte file length.
- // WAVE header: 4 bytes consisting of the signature "WAVE".
- // fmt header: 4 bytes consisting of the signature "fmt " followed by a WAVEFORMATEX
- // WAVEFORMAT: <n> bytes containing a waveformat structure.
- // DATA header: 8 bytes consisting of the signature "data" followed by a 4 byte file length.
- // wave data: <m> bytes containing wave data.
- //
- //
- // Header for a WAV file - we define a structure describing the first few fields in the header for convenience.
- //
- struct WAVEHEADER
- {
- DWORD dwRiff; // "RIFF"
- DWORD dwSize; // Size
- DWORD dwWave; // "WAVE"
- DWORD dwFmt; // "fmt "
- DWORD dwFmtSize; // Wave Format Size
- };
- // Static RIFF header, we'll append the format to it.
- const BYTE WaveHeader[] = {'R', 'I', 'F', 'F', 0x00, 0x00, 0x00, 0x00, 'W', 'A',
- 'V', 'E', 'f', 'm', 't', ' ', 0x00, 0x00, 0x00, 0x00};
- // Static wave DATA tag.
- const BYTE WaveData[] = {'d', 'a', 't', 'a'};
- //
- // Write the contents of a WAV file. We take as input the data to write and the format of that data.
- //
- bool WriteWaveFile(HANDLE FileHandle,
- const BYTE *Buffer,
- const size_t BufferSize,
- const WAVEFORMATEX *WaveFormat)
- {
- DWORD waveFileSize = sizeof(WAVEHEADER) + sizeof(WAVEFORMATEX) + WaveFormat->cbSize
- + sizeof(WaveData) + sizeof(DWORD) + static_cast<DWORD>(BufferSize);
- BYTE *waveFileData = new (std::nothrow) BYTE[waveFileSize];
- BYTE *waveFilePointer = waveFileData;
- WAVEHEADER *waveHeader = reinterpret_cast<WAVEHEADER *>(waveFileData);
- if (waveFileData == NULL) {
- printf("Unable to allocate %d bytes to hold output wave data\n", waveFileSize);
- return false;
- }
- //
- // Copy in the wave header - we'll fix up the lengths later.
- //
- CopyMemory(waveFilePointer, WaveHeader, sizeof(WaveHeader));
- waveFilePointer += sizeof(WaveHeader);
- //
- // Update the sizes in the header.
- //
- waveHeader->dwSize = waveFileSize - (2 * sizeof(DWORD));
- waveHeader->dwFmtSize = sizeof(WAVEFORMATEX) + WaveFormat->cbSize;
- //
- // Next copy in the WaveFormatex structure.
- //
- CopyMemory(waveFilePointer, WaveFormat, sizeof(WAVEFORMATEX) + WaveFormat->cbSize);
- waveFilePointer += sizeof(WAVEFORMATEX) + WaveFormat->cbSize;
- //
- // Then the data header.
- //
- CopyMemory(waveFilePointer, WaveData, sizeof(WaveData));
- waveFilePointer += sizeof(WaveData);
- *(reinterpret_cast<DWORD *>(waveFilePointer)) = static_cast<DWORD>(BufferSize);
- waveFilePointer += sizeof(DWORD);
- //
- // And finally copy in the audio data.
- //
- CopyMemory(waveFilePointer, Buffer, BufferSize);
- //
- // Last but not least, write the data to the file.
- //
- DWORD bytesWritten;
- if (!WriteFile(FileHandle, waveFileData, waveFileSize, &bytesWritten, NULL)) {
- printf("Unable to write wave file: %d\n", GetLastError());
- delete[] waveFileData;
- return false;
- }
- if (bytesWritten != waveFileSize) {
- printf("Failed to write entire wave file\n");
- delete[] waveFileData;
- return false;
- }
- delete[] waveFileData;
- return true;
- }
- //
- // Write the captured wave data to an output file so that it can be examined later.
- //
- void SaveWaveData(BYTE *CaptureBuffer, size_t BufferSize, const WAVEFORMATEX *WaveFormat)
- {
- HRESULT hr = NOERROR;
- SYSTEMTIME st;
- GetLocalTime(&st);
- char waveFileName[_MAX_PATH] = {0};
- sprintf(waveFileName,
- ".\\WAS_%04d-%02d-%02d_%02d_%02d_%02d_%02d.wav",
- st.wYear,
- st.wMonth,
- st.wDay,
- st.wHour,
- st.wMinute,
- st.wSecond,
- st.wMilliseconds);
- HANDLE waveHandle = CreateFile(waveFileName,
- GENERIC_WRITE,
- FILE_SHARE_READ,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
- NULL);
- if (waveHandle != INVALID_HANDLE_VALUE) {
- if (WriteWaveFile(waveHandle, CaptureBuffer, BufferSize, WaveFormat)) {
- printf("Successfully wrote WAVE data to %s\n", waveFileName);
- } else {
- printf("Unable to write wave file\n");
- }
- CloseHandle(waveHandle);
- } else {
- printf("Unable to open output WAV file %s: %d\n", waveFileName, GetLastError());
- }
- }
- static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt);
- static int select_sample_rate(const AVCodec *codec);
- BOOL AdjustFormatTo16Bits(WAVEFORMATEX *pwfx)
- {
- BOOL bRet(FALSE);
- if (pwfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
- pwfx->wFormatTag = WAVE_FORMAT_PCM;
- pwfx->wBitsPerSample = 16;
- pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
- pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
- bRet = TRUE;
- } else if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
- PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
- if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat)) {
- pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- pEx->Samples.wValidBitsPerSample = 16;
- pwfx->wBitsPerSample = 16;
- pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
- pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
- bRet = TRUE;
- }
- }
- return bRet;
- }
- #define DEF_CAPTURE_MIC
- HRESULT capture_audio()
- {
- HRESULT hr;
- REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
- REFERENCE_TIME hnsActualDuration;
- UINT32 bufferFrameCount;
- UINT32 numFramesAvailable;
- IMMDeviceEnumerator *pEnumerator = NULL;
- IMMDevice *pDevice = NULL;
- IAudioClient *pAudioClient = NULL;
- IAudioCaptureClient *pCaptureClient = NULL;
- WAVEFORMATEX *pwfx = NULL;
- UINT32 packetLength = 0;
- BOOL bDone = FALSE;
- BYTE *pData;
- DWORD flags;
- /*CoTaskMemFree(pwfx);
- SAFE_RELEASE(pEnumerator)
- SAFE_RELEASE(pDevice)
- SAFE_RELEASE(pAudioClient)
- SAFE_RELEASE(pCaptureClient)*/
- hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
- hr = CoCreateInstance(CLSID_MMDeviceEnumerator,
- NULL,
- CLSCTX_ALL,
- IID_IMMDeviceEnumerator,
- (void **) &pEnumerator);
- EXIT_ON_ERROR(hr)
- hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
- EXIT_ON_ERROR(hr)
- hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &pAudioClient);
- EXIT_ON_ERROR(hr)
- hr = pAudioClient->GetMixFormat(&pwfx);
- EXIT_ON_ERROR(hr)
- //AdjustFormatTo16Bits(pwfx);
- hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
- hnsRequestedDuration,
- 0,
- pwfx,
- NULL);
- EXIT_ON_ERROR(hr)
- size_t persample_size = (pwfx->wBitsPerSample / 8) * pwfx->nChannels;
- // Get the size of the allocated buffer.
- hr = pAudioClient->GetBufferSize(&bufferFrameCount);
- EXIT_ON_ERROR(hr)
- hr = pAudioClient->GetService(IID_IAudioCaptureClient, (void **) &pCaptureClient);
- EXIT_ON_ERROR(hr)
- // Calculate the actual duration of the allocated buffer.
- hnsActualDuration = (double) REFTIMES_PER_SEC * bufferFrameCount / pwfx->nSamplesPerSec;
- av_register_all();
- AVIOContext *output_io_context = NULL;
- AVFormatContext *output_format_context = NULL;
- AVCodecContext *output_codec_context = NULL;
- AVStream *output_stream = NULL;
- AVCodec *output_codec = NULL;
- const char *out_file = "tdjm.aac";
- if (avio_open(&output_io_context, out_file, AVIO_FLAG_READ_WRITE) < 0) {
- printf("Failed to open output file!\n");
- return -1;
- }
- output_format_context = avformat_alloc_context();
- if (output_format_context == NULL) {
- return -1;
- }
- output_format_context->pb = output_io_context;
- output_format_context->oformat = av_guess_format(NULL, out_file, NULL);
- output_format_context->url = av_strdup(out_file);
- if (!(output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC)))
- return -1;
- int is_support = check_sample_fmt(output_codec, AV_SAMPLE_FMT_S16);
- int selected_sample = select_sample_rate(output_codec);
- output_stream = avformat_new_stream(output_format_context, NULL);
- if (!output_stream)
- return -1;
- output_codec_context = avcodec_alloc_context3(output_codec);
- if (output_codec_context == NULL)
- return -1;
- output_codec_context->channels
- = 2; //av_get_channel_layout_nb_channels(pEncoderCtx->channel_layout);
- output_codec_context->channel_layout = ffmpeg_get_default_channel_layout(2); //AV_CH_LAYOUT_STEREO;
- output_codec_context->sample_rate = pwfx->nSamplesPerSec; //48000
- output_codec_context->sample_fmt = AV_SAMPLE_FMT_FLTP;
- output_codec_context->bit_rate = 96000;
- output_codec_context->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
- output_codec_context->time_base.den = pwfx->nSamplesPerSec;
- output_codec_context->time_base.num = 1;
- if (output_format_context->oformat->flags & AVFMT_GLOBALHEADER) {
- output_format_context->oformat->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
- }
- if (avcodec_open2(output_codec_context, output_codec, NULL) < 0)
- throw std::exception("open audio encoder failed");
- if (avcodec_parameters_from_context(output_stream->codecpar, output_codec_context) < 0)
- return -1;
- AVFrame *resampled_frame = av_frame_alloc();
- resampled_frame->nb_samples = output_codec_context->frame_size;
- resampled_frame->channel_layout = output_codec_context->channel_layout;
- resampled_frame->format = output_codec_context->sample_fmt;
- resampled_frame->sample_rate = output_codec_context->sample_rate;
- int resampled_size = av_samples_get_buffer_size(NULL,
- output_codec_context->channels,
- output_codec_context->frame_size,
- output_codec_context->sample_fmt,
- 0);
- uint8_t *resampled_buf = (uint8_t *) av_malloc(resampled_size);
- if (avcodec_fill_audio_frame(resampled_frame,
- output_codec_context->channels,
- output_codec_context->sample_fmt,
- resampled_buf,
- resampled_size,
- 0)
- < 0)
- return -1;
- AVFrame *sample_frame = av_frame_alloc();
- sample_frame->nb_samples = 1024;
- sample_frame->channel_layout = ffmpeg_get_default_channel_layout(pwfx->nChannels);
- sample_frame->format = AV_SAMPLE_FMT_FLT;
- sample_frame->sample_rate = pwfx->nSamplesPerSec;
- int sample_size = av_samples_get_buffer_size(NULL, pwfx->nChannels, 1024, AV_SAMPLE_FMT_FLT, 0);
- uint8_t *sample_buf = (uint8_t *) av_malloc(sample_size);
- avcodec_fill_audio_frame(sample_frame,
- pwfx->nChannels,
- AV_SAMPLE_FMT_FLT,
- sample_buf,
- sample_size,
- 0);
- AVPacket pkt;
- HANDLE hAudioSamplesReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (hAudioSamplesReadyEvent == NULL) {
- printf("Unable to create samples ready event: %d.\n", GetLastError());
- goto Exit;
- }
- hr = pAudioClient->SetEventHandle(hAudioSamplesReadyEvent);
- if (FAILED(hr)) {
- printf("Unable to set ready event: %x.\n", hr);
- return false;
- }
- //init resampler
- SwrContext *resample_ctx = swr_alloc_set_opts(NULL,
- AV_CH_LAYOUT_STEREO,
- AV_SAMPLE_FMT_FLTP,
- 48000,
- AV_CH_LAYOUT_STEREO,
- AV_SAMPLE_FMT_FLT,
- 48000,
- 0,
- NULL);
- int error = swr_init(resample_ctx);
- if (error < 0)
- return false;
- //init FIFO buffer
- //start recording
- avformat_write_header(output_format_context, NULL);
- hr = pAudioClient->Start();
- EXIT_ON_ERROR(hr)
- int pcmInBuffer = 0;
- int copiedPcm = 0;
- int gotPacket = 0;
- int index = 0;
- HANDLE waitArray[3];
- waitArray[0] = hAudioSamplesReadyEvent;
- uint64_t nextptx = 0;
- while (bDone == false) {
- DWORD waitResult = WaitForMultipleObjects(1, waitArray, FALSE, INFINITE);
- switch (waitResult) {
- case WAIT_OBJECT_0 + 0: // _AudioSamplesReadyEvent
- hr = pCaptureClient->GetNextPacketSize(&packetLength);
- while (packetLength != 0) {
- // Get the available data in the shared buffer.
- hr = pCaptureClient->GetBuffer(&pData, &numFramesAvailable, &flags, NULL, NULL);
- if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
- pData = NULL; // Tell CopyData to write silence.
- }
- // Copy the available capture data to the audio sink.
- if (pData != NULL) {
- copiedPcm = min(sample_size - pcmInBuffer, numFramesAvailable * persample_size);
- if (copiedPcm > 0) {
- memcpy(sample_buf + pcmInBuffer, pData, copiedPcm);
- pcmInBuffer += copiedPcm;
- }
- if (pcmInBuffer == sample_size) { //got one frame ,encode
- int ret = swr_convert(resample_ctx,
- resampled_frame->data,
- output_codec_context->frame_size,
- (const uint8_t **) sample_frame->data,
- 1024);
- if (ret <= 0)
- return -1;
- av_init_packet(&pkt);
- resampled_frame->pts = nextptx;
- nextptx += resampled_frame->nb_samples;
- int error = avcodec_send_frame(output_codec_context, resampled_frame);
- if (error == 0) {
- error = avcodec_receive_packet(output_codec_context, &pkt);
- if (error == 0) {
- av_write_frame(output_format_context, &pkt);
- index++;
- printf("index:%d\r\n", index);
- }
- av_packet_unref(&pkt);
- }
- pcmInBuffer = 0;
- }
- if (numFramesAvailable * persample_size - copiedPcm > 0) {
- memcpy(sample_buf + pcmInBuffer,
- pData + copiedPcm,
- numFramesAvailable * persample_size - copiedPcm);
- pcmInBuffer += numFramesAvailable * persample_size - copiedPcm;
- }
- if (index > 2000) {
- printf("pcm still in buffer:%d\r\n", pcmInBuffer);
- bDone = true;
- break;
- }
- }
- hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);
- EXIT_ON_ERROR(hr)
- hr = pCaptureClient->GetNextPacketSize(&packetLength);
- EXIT_ON_ERROR(hr)
- }
- break;
- } // end of 'switch (waitResult)'
- } // end of 'while (stillPlaying)'
- av_write_trailer(output_format_context);
- if (output_codec_context)
- avcodec_free_context(&output_codec_context);
- if (output_format_context) {
- avio_closep(&output_format_context->pb);
- avformat_free_context(output_format_context);
- }
- hr = pAudioClient->Stop(); // Stop recording.
- EXIT_ON_ERROR(hr)
- Exit:
- CoTaskMemFree(pwfx);
- SAFE_RELEASE(pEnumerator)
- SAFE_RELEASE(pDevice)
- SAFE_RELEASE(pAudioClient)
- SAFE_RELEASE(pCaptureClient)
- return hr;
- }
- HRESULT cpature_wave()
- {
- HRESULT hr;
- IMMDeviceEnumerator *pEnumerator = NULL;
- IMMDevice *pDevice = NULL;
- IAudioClient *pAudioClient = NULL;
- IAudioCaptureClient *pCaptureClient = NULL;
- WAVEFORMATEX *pwfx = NULL;
- REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;
- UINT32 bufferFrameCount;
- UINT32 numFramesAvailable;
- BYTE *pData;
- UINT32 packetLength = 0;
- DWORD flags;
- hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
- if (FAILED(hr)) {
- printf("Unable to initialize COM in thread: %x\n", hr);
- return hr;
- }
- hr = CoCreateInstance(CLSID_MMDeviceEnumerator,
- NULL,
- CLSCTX_ALL,
- IID_IMMDeviceEnumerator,
- (void **) &pEnumerator);
- EXIT_ON_ERROR(hr)
- #ifdef DEF_CAPTURE_MIC
- hr = pEnumerator->GetDefaultAudioEndpoint(eCapture, eCommunications, &pDevice);
- //hr = pEnumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &pDevice);
- #else
- hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
- #endif
- EXIT_ON_ERROR(hr)
- hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **) &pAudioClient);
- EXIT_ON_ERROR(hr)
- hr = pAudioClient->GetMixFormat(&pwfx);
- EXIT_ON_ERROR(hr)
- AdjustFormatTo16Bits(pwfx);
- #ifdef DEF_CAPTURE_MIC
- hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
- hnsRequestedDuration,
- 0,
- pwfx,
- NULL);
- #else
- /*
- The AUDCLNT_STREAMFLAGS_LOOPBACK flag enables loopback recording.
- In loopback recording, the audio engine copies the audio stream
- that is being played by a rendering endpoint device into an audio endpoint buffer
- so that a WASAPI client can capture the stream.
- If this flag is set, the IAudioClient::Initialize method attempts to open a capture buffer on the rendering device.
- This flag is valid only for a rendering device
- and only if the Initialize call sets the ShareMode parameter to AUDCLNT_SHAREMODE_SHARED.
- Otherwise the Initialize call will fail.
- If the call succeeds,
- the client can call the IAudioClient::GetService method
- to obtain an IAudioCaptureClient interface on the rendering device.
- For more information, see Loopback Recording.
- */
- hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_LOOPBACK,
- hnsRequestedDuration,
- 0,
- pwfx,
- NULL);
- #endif
- EXIT_ON_ERROR(hr)
- int nFrameSize = (pwfx->wBitsPerSample / 8) * pwfx->nChannels;
- REFERENCE_TIME hnsStreamLatency;
- hr = pAudioClient->GetStreamLatency(&hnsStreamLatency);
- EXIT_ON_ERROR(hr)
- REFERENCE_TIME hnsDefaultDevicePeriod;
- REFERENCE_TIME hnsMinimumDevicePeriod;
- hr = pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, &hnsMinimumDevicePeriod);
- EXIT_ON_ERROR(hr)
- hr = pAudioClient->GetBufferSize(&bufferFrameCount);
- EXIT_ON_ERROR(hr)
- std::cout << std::endl << "GetBufferSize : " << bufferFrameCount << std::endl;
- // SetEventHandle
- //////////////////////////////////////////////////////////////////////////
- HANDLE hAudioSamplesReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (hAudioSamplesReadyEvent == NULL) {
- printf("Unable to create samples ready event: %d.\n", GetLastError());
- goto Exit;
- }
- hr = pAudioClient->SetEventHandle(hAudioSamplesReadyEvent);
- if (FAILED(hr)) {
- printf("Unable to set ready event: %x.\n", hr);
- return false;
- }
- //////////////////////////////////////////////////////////////////////////
- hr = pAudioClient->GetService(IID_IAudioCaptureClient, (void **) &pCaptureClient);
- EXIT_ON_ERROR(hr)
- hr = pAudioClient->Start(); // Start recording.
- EXIT_ON_ERROR(hr)
- printf("\nAudio Capture begin...\n\n");
- int nCnt = 0;
- size_t nCaptureBufferSize = 8 * 1024 * 1024;
- size_t nCurrentCaptureIndex = 0;
- BYTE *pbyCaptureBuffer = new (std::nothrow) BYTE[nCaptureBufferSize];
- HANDLE waitArray[3];
- waitArray[0] = hAudioSamplesReadyEvent;
- bool stillPlaying = true;
- // Each loop fills about half of the shared buffer.
- while (stillPlaying) {
- DWORD waitResult = WaitForMultipleObjects(1, waitArray, FALSE, INFINITE);
- switch (waitResult) {
- case WAIT_OBJECT_0 + 0: // _AudioSamplesReadyEvent
- hr = pCaptureClient->GetNextPacketSize(&packetLength);
- EXIT_ON_ERROR(hr)
- printf("%06d # _AudioSamplesReadyEvent packetLength:%06u \n", nCnt, packetLength);
- while (packetLength != 0) {
- // Get the available data in the shared buffer.
- hr = pCaptureClient->GetBuffer(&pData, &numFramesAvailable, &flags, NULL, NULL);
- EXIT_ON_ERROR(hr)
- nCnt++;
- // test flags
- //////////////////////////////////////////////////////////////////////////
- if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
- printf("AUDCLNT_BUFFERFLAGS_SILENT \n");
- }
- if (flags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY) {
- printf("%06d # AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY \n", nCnt);
- }
- //////////////////////////////////////////////////////////////////////////
- UINT32 framesToCopy = min(numFramesAvailable,
- static_cast<UINT32>(
- (nCaptureBufferSize - nCurrentCaptureIndex)
- / nFrameSize));
- if (framesToCopy != 0) {
- //
- // The flags on capture tell us information about the data.
- //
- // We only really care about the silent flag since we want to put frames of silence into the buffer
- // when we receive silence. We rely on the fact that a logical bit 0 is silence for both float and int formats.
- //
- if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
- //
- // Fill 0s from the capture buffer to the output buffer.
- //
- ZeroMemory(&pbyCaptureBuffer[nCurrentCaptureIndex],
- framesToCopy * nFrameSize);
- } else {
- //
- // Copy data from the audio engine buffer to the output buffer.
- //
- CopyMemory(&pbyCaptureBuffer[nCurrentCaptureIndex],
- pData,
- framesToCopy * nFrameSize);
- printf("Get: %d\r\n", framesToCopy * nFrameSize);
- }
- //
- // Bump the capture buffer pointer.
- //
- nCurrentCaptureIndex += framesToCopy * nFrameSize;
- }
- hr = pCaptureClient->ReleaseBuffer(numFramesAvailable);
- EXIT_ON_ERROR(hr)
- hr = pCaptureClient->GetNextPacketSize(&packetLength);
- EXIT_ON_ERROR(hr)
- UINT32 ui32NumPaddingFrames;
- hr = pAudioClient->GetCurrentPadding(&ui32NumPaddingFrames);
- EXIT_ON_ERROR(hr)
- if (0 != ui32NumPaddingFrames) {
- printf("GetCurrentPadding : %6u\n", ui32NumPaddingFrames);
- }
- //////////////////////////////////////////////////////////////////////////
- if (nCnt == 1000) {
- stillPlaying = false;
- break;
- }
- } // end of 'while (packetLength != 0)'
- break;
- } // end of 'switch (waitResult)'
- } // end of 'while (stillPlaying)'
- //
- // We've now captured our wave data. Now write it out in a wave file.
- //
- SaveWaveData(pbyCaptureBuffer, nCurrentCaptureIndex, pwfx);
- printf("\nAudio Capture Done.\n");
- hr = pAudioClient->Stop(); // Stop recording.
- EXIT_ON_ERROR(hr)
- Exit:
- CoTaskMemFree(pwfx);
- SAFE_RELEASE(pEnumerator)
- SAFE_RELEASE(pDevice)
- SAFE_RELEASE(pAudioClient)
- SAFE_RELEASE(pCaptureClient)
- CoUninitialize();
- if (pbyCaptureBuffer) {
- delete[] pbyCaptureBuffer;
- pbyCaptureBuffer = NULL;
- }
- if (hAudioSamplesReadyEvent) {
- CloseHandle(hAudioSamplesReadyEvent);
- hAudioSamplesReadyEvent = NULL;
- }
- }
- /* check that a given sample format is supported by the encoder */
- static int check_sample_fmt(const AVCodec *codec, enum AVSampleFormat sample_fmt)
- {
- const enum AVSampleFormat *p = codec->sample_fmts;
- while (*p != AV_SAMPLE_FMT_NONE) {
- if (*p == sample_fmt)
- return 1;
- p++;
- }
- return 0;
- }
- /* just pick the highest supported samplerate */
- static int select_sample_rate(const AVCodec *codec)
- {
- const int *p;
- int best_samplerate = 0;
- if (!codec->supported_samplerates)
- return 44100;
- p = codec->supported_samplerates;
- while (*p) {
- if (!best_samplerate || abs(44100 - *p) < abs(44100 - best_samplerate))
- best_samplerate = *p;
- p++;
- }
- return best_samplerate;
- }
- /* select layout with the highest channel count */
- static int select_channel_layout(const AVCodec *codec)
- {
- const uint64_t *p;
- uint64_t best_ch_layout = 0;
- int best_nb_channels = 0;
- if (!codec->channel_layouts)
- return AV_CH_LAYOUT_STEREO;
- p = codec->channel_layouts;
- while (*p) {
- int nb_channels = av_get_channel_layout_nb_channels(*p);
- if (nb_channels > best_nb_channels) {
- best_ch_layout = *p;
- best_nb_channels = nb_channels;
- }
- p++;
- }
- return best_ch_layout;
- }
- int main1()
- {
- //capture_audio();
- //test_transcode();
- cpature_wave();
- system("pause");
- return 0;
- }
|