// Recorder.cpp : Defines the entry point for the console application. // #include #include 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); } } // 移除固定睡眠以降低延迟,依靠事件/时间戳节奏 } 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 #include #include #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: bytes containing a waveformat structure. // DATA header: 8 bytes consisting of the signature "data" followed by a 4 byte file length. // wave data: 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(BufferSize); BYTE *waveFileData = new (std::nothrow) BYTE[waveFileSize]; BYTE *waveFilePointer = waveFileData; WAVEHEADER *waveHeader = reinterpret_cast(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(waveFilePointer)) = static_cast(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(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( (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; }