I'm attempting to decode frames, but memory usage grows with every frame (more specifically, with every call to avcodec_send_packet) until finally the code crashes with a bad_alloc. Here's the basic decode loop:
int rfret = 0;
while((rfret = av_read_frame(inctx.get(), &packet)) >= 0){
if (packet.stream_index == vstrm_idx) {
//std::cout << "Sending Packet" << std::endl;
int ret = avcodec_send_packet(ctx.get(), &packet);
if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
std::cout << "avcodec_send_packet: " << ret << std::endl;
break;
}
while (ret >= 0) {
//std::cout << "Receiving Frame" << std::endl;
ret = avcodec_receive_frame(ctx.get(), fr);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
//std::cout << "avcodec_receive_frame: " << ret << std::endl;
av_frame_unref(fr);
// av_frame_free(&fr);
break;
}
std::cout << "frame: " << ctx->frame_number << std::endl;
// eventually do something with the frame here...
av_frame_unref(fr);
// av_frame_free(&fr);
}
}
else {
//std::cout << "Not Video" << std::endl;
}
av_packet_unref(&packet);
}
Memory usage/leakage seems to scale with the resolution of the video I'm decoding. For example, for a 3840x2160 resolution video, the memory usage in windows task manager consistently jumps up by about 8mb (1 byte per pixel??) for each received frame. Do I need to do something besides call av_frame_unref to release the memory?
(more) complete code below
void AVFormatContextDeleter(AVFormatContext* ptr)
{
if (ptr) {
avformat_close_input(&ptr);
}
}
void AVCodecContextDeleter(AVCodecContext* ptr)
{
if (ptr) {
avcodec_free_context(&ptr);
}
}
typedef std::unique_ptr<AVFormatContext, void (*)(AVFormatContext *)> AVFormatContextPtr;
typedef std::unique_ptr<AVCodecContext, void (*)(AVCodecContext *)> AVCodecContextPtr;
AVCodecContextPtr createAvCodecContext(AVCodec *vcodec)
{
AVCodecContextPtr ctx(avcodec_alloc_context3(vcodec), AVCodecContextDeleter);
return ctx;
}
AVFormatContextPtr createFormatContext(const std::string& filename)
{
AVFormatContext* inctxPtr = nullptr;
int ret = avformat_open_input(&inctxPtr, filename.c_str(), nullptr, nullptr);
// int ret = avformat_open_input(&inctx, "D:/Videos/test.mp4", nullptr, nullptr);
if (ret != 0) {
inctxPtr = nullptr;
}
return AVFormatContextPtr(inctxPtr, AVFormatContextDeleter);
}
int testDecode()
{
// open input file context
AVFormatContextPtr inctx = createFormatContext("D:/Videos/Matt Chapman Hi Greg.MOV");
if (!inctx) {
// std::cerr << "fail to avforamt_open_input(\"" << infile << "\"): ret=" << ret;
return 1;
}
// retrieve input stream information
int ret = avformat_find_stream_info(inctx.get(), nullptr);
if (ret < 0) {
//std::cerr << "fail to avformat_find_stream_info: ret=" << ret;
return 2;
}
// find primary video stream
AVCodec* vcodec = nullptr;
const int vstrm_idx = av_find_best_stream(inctx.get(), AVMEDIA_TYPE_VIDEO, -1, -1, &vcodec, 0);
if (vstrm_idx < 0) {
//std::cerr << "fail to av_find_best_stream: vstrm_idx=" << vstrm_idx;
return 3;
}
AVCodecParameters* origin_par = inctx->streams[vstrm_idx]->codecpar;
if (vcodec == nullptr) { // is this even necessary?
vcodec = avcodec_find_decoder(origin_par->codec_id);
if (!vcodec) {
// Can't find decoder
return 4;
}
}
AVCodecContextPtr ctx = createAvCodecContext(vcodec);
if (!ctx) {
return 5;
}
ret = avcodec_parameters_to_context(ctx.get(), origin_par);
if (ret) {
return 6;
}
ret = avcodec_open2(ctx.get(), vcodec, nullptr);
if (ret < 0) {
return 7;
}
//print input video stream informataion
std::cout
//<< "infile: " << infile << "\n"
<< "format: " << inctx->iformat->name << "\n"
<< "vcodec: " << vcodec->name << "\n"
<< "size: " << origin_par->width << 'x' << origin_par->height << "\n"
<< "fps: " << av_q2d(ctx->framerate) << " [fps]\n"
<< "length: " << av_rescale_q(inctx->duration, ctx->time_base, {1,1000}) / 1000. << " [sec]\n"
<< "pixfmt: " << av_get_pix_fmt_name(ctx->pix_fmt) << "\n"
<< "frame: " << inctx->streams[vstrm_idx]->nb_frames << "\n"
<< std::flush;
AVPacket packet;
av_init_packet(&packet);
packet.data = nullptr;
packet.size = 0;
AVFrame *fr = av_frame_alloc();
if (!fr) {
return 8;
}
int rfret = 0;
while((rfret = av_read_frame(inctx.get(), &packet)) >= 0){
if (packet.stream_index == vstrm_idx) {
//std::cout << "Sending Packet" << std::endl;
int ret = avcodec_send_packet(ctx.get(), &packet);
if (ret < 0 || ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
std::cout << "avcodec_send_packet: " << ret << std::endl;
break;
}
while (ret >= 0) {
//std::cout << "Receiving Frame" << std::endl;
ret = avcodec_receive_frame(ctx.get(), fr);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
//std::cout << "avcodec_receive_frame: " << ret << std::endl;
av_frame_unref(fr);
// av_frame_free(&fr);
break;
}
std::cout << "frame: " << ctx->frame_number << std::endl;
// do something with the frame here...
av_frame_unref(fr);
// av_frame_free(&fr);
}
}
else {
//std::cout << "Not Video" << std::endl;
}
av_packet_unref(&packet);
}
std::cout << "RFRET = " << rfret << std::endl;
return 0;
}
Update 1: (1/21/2019) Compiling on a different machine and running with different video files I am not seeing the memory usage growing without bound. I'll try to narrow down where the difference lies (compiler?, ffmpeg version?, or video encoding?)
Update 2: (1/21/2019) Ok, it looks like there is some interaction occurring between ffmpeg and Qt's QCamera. In my application, I'm using Qt to manage the webcam, but decided to use ffmpeg libraries to handle decoding/encoding since Qt doesn't have as comprehensive support for different codecs. If I have the camera turned on (through Qt), ffmpeg decoding memory consumption grows without bound. If the camera is off, ffmpeg behaves fine. I've tried this both with a physical camera (Logitech C920) and with a virtual camera using OBS-Virtualcam, with the same result. So far I'm baffled as to how the two systems are interacting...
I had same problem.
before use the av_frame_unref.
call av_freep(buffer->data[0]).
av_frame_unref was not release raw data in frame
example:
av_freep(&pFrame->data[0]);
av_frame_unref(pFrame);
//av_free(pFrame);
EDIT:
I am sorry that English is immature.
When you decode the video, you have the data for the image in the buffer.
It will remain as a NULL pointer until you release it and reallocate it, which means that you will need to allocate memory again at reallocation.
After you have finished using the image data, you should release the buffer.
Are you using it like that?
while (Framecheck = av_read_frame(pFormatCtx, &packet) == NULL ) {
if (d_end == true)
break;
if (packet.stream_index == VSI) {
if (bool res = avcodec_send_packet(pVideoCodecCtx, &packet)) {
printf("avcodec_send_packet failed %d %d %d\n", res, AVERROR(EINVAL), AVERROR(ENOMEM));
}
if (bool res = avcodec_receive_frame(pVideoCodecCtx, pVFrame) == 0) {
printf("avcodec_receive failed %d %d %d\n", res, AVERROR(EINVAL), AVERROR(ENOMEM));
}
if (pVFrame->data[0] == NULL && pVFrame->data[1] == NULL && pVFrame->data[2] == NULL)
continue;
else {
YUV_frame = Con_yuv_RGB(pVFrame);
QFrame->push(YUV_frame);
PushCount++;
}
}
Sleep(5);
}
if (Framecheck != true){
av_packet_unref(&packet);
d_end = true;
return true;
release:
if (FrameQueue->size()) {
while (FrameQueue->size() > 0) {
av_freep(&FrameQueue->front());
//av_frame_unref(FrameQueue->front());
av_free(FrameQueue->front());
FrameQueue->pop();
}
}
Try calling av_frame_free when you're done with the frame (outside your while loop)
And don't call av_frame_unref
See example here:
https://ffmpeg.org/doxygen/4.0/decode__video_8c_source.html
Related
My setsockopt() call is returning -1, I used WSAGetLastError() which returns WSAEFAULT.
WSAEFAULT
10014
Bad address.
The system detected an invalid pointer address in attempting to use a pointer argument of a call. This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small. For instance, if the length of an argument, which is a sockaddr structure, is smaller than the sizeof(sockaddr).
I am using MSVC 2022
#include<iostream>
#include<WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
#define PORT 9909
struct sockaddr_in srv;
fd_set fr, fw, fe;
int nMaxFd;
int main() {
int nRet = 0;
// Initialize the WSA variables
WSADATA ws;
if (WSAStartup(MAKEWORD(2, 2), &ws) < 0) {
cout << endl << "WSA failed to initialize";
WSACleanup();
exit(EXIT_FAILURE);
}
else
cout << endl << "WSA initialized";
// Initialize the socket
int nSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (nSocket < 0) {
cout << endl << "The socket not opened";
WSACleanup();
exit(EXIT_FAILURE);
}
else {
cout << endl << "The socket opened successfully"<<nSocket;
}
// Initialize the environment for sockaddr structure
srv.sin_family = AF_INET;
srv.sin_port = htons(PORT);
srv.sin_addr.s_addr = INADDR_ANY;
memset(srv.sin_zero, 0, 8);
// setsockpot
int nOptVal = 1;
int nOptLen = sizeof(nOptVal);
nRet = setsockopt(nSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)nOptVal, nOptLen);
cout << nRet;
if (!nRet) {
cout << endl << "The setsockopt call successful";
}
else {
cout << endl << "THe setsockopt call failed";
cout << endl << WSAGetLastError();
WSACleanup();
exit(EXIT_FAILURE);
}
/* In default, every socket is Blocking socket, we have to use explicitly if wer want non blocking sockets
// About the Blocking and Non Blocking sockets
u_long optval = 0;
nRet = ioctlsocket(nSocket, FIONBIO, &optval);
if (nRet != 0) {
cout << endl << "ioctlsocket call failed";
}
else {
cout << endl << "ioctlsocket call passed";
}
*/
/*
// Bind the socket to the local port
nRet = bind(nSocket, (sockaddr*)&srv, sizeof(sockaddr));
if (nRet < 0) {
cout << endl << "Fail to bind to local port";
exit(EXIT_FAILURE);
}
else
cout << endl << "Successfully bind to local port";
// Listen the request from client (queues the requests)
nRet = listen(nSocket, 5);
if (nRet < 0) {
cout << endl << "Fail to start listen to local port";
WSACleanup();
exit(EXIT_FAILURE);
}
else {
cout << endl << "Started listening to local port";
}
nMaxFd = nSocket;
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
while (1) {
FD_ZERO(&fr);
FD_ZERO(&fw);
FD_ZERO(&fe);
FD_SET(nSocket, &fr);
FD_SET(nSocket, &fe);
cout << endl << "Before select call: " << fr.fd_count;
// Keep waiting for new requests and proceed as per the request
nRet = select(nMaxFd + 1, &fr, &fw, &fe, &tv);
if (nRet > 0) {
// When someone connects or communicates with a message over a dedicated connection
}
else if (nRet == 0) {
// No connection or any communication request made or you can say that none of the
// socket descriptors are ready
cout << endl << "Nothing on port: " << PORT;
}
else {
// It failed and your application should show some useful message
cout << endl << "I failed...";
WSACleanup();
exit(EXIT_FAILURE);
}
cout << endl << "After the select call: " << fr.fd_count;
}
*/
}
I assumed my setsockopt() will return 0, but it returns -1:
int nOptVal = 1;
int nOptLen = sizeof(nOptVal);
nRet = setsockopt(nSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)nOptVal, nOptLen);
Per the setsockopt() documentation, the WSAEFAULT error is telling you that you are passing in an invalid pointer in the optval parameter:
Error code
Meaning
WSAEFAULT
The buffer pointed to by the optval parameter is not in a valid part of the process address space or the optlen parameter is too small.
When calling setsockopt(), you need to pass in the memory address of the nOptVal variable, but you are passing in its value instead, typecasted to a pointer. 1 is not a valid memory address of the variable, hence the error.
Try this instead:
int nOptVal = 1;
int nOptLen = sizeof(nOptVal);
nRet = setsockopt(nSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOptVal, nOptLen);
^
add this!
I am trying to run a tcp server on my machine, this is mostly a tutorial code but for some reason the bind is failing with error 10014. sizeof(serverAddr) returns 16 in the below code if anyone is interested. I know what error 10014 means but can't seem to figure out why it's coming here on bind everything seems ok.
#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
int main()
{
WSADATA WSAData;
SOCKET server, client;
SOCKADDR_IN serverAddr, clientAddr;
int iResult = WSAStartup(MAKEWORD(2, 2), &WSAData);
if (iResult != NO_ERROR) {
std::cout << "startup error" << std::endl;
return 1;
}
server = socket(AF_INET, SOCK_STREAM, 0);
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(5555);
if (bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr) != 0))
{
std::cout << "bind " << WSAGetLastError() << " sizeof " << sizeof(serverAddr) << std::endl;
std::cout << "cannot start server" << std::endl;
return 0;
}
listen(server, 0);
std::cout << "Listening for incoming connections..." << std::endl;
char buffer[1024];
int clientAddrSize = sizeof(clientAddr);
if ((client = accept(server, (SOCKADDR*)&clientAddr, &clientAddrSize)) != INVALID_SOCKET)
{
std::cout << "Client connected!" << std::endl;
recv(client, buffer, sizeof(buffer), 0);
std::cout << "Client says: " << buffer << std::endl;
memset(buffer, 0, sizeof(buffer));
closesocket(client);
std::cout << "Client disconnected." << std::endl;
}
return 0;
}
There is an error with the parantheses. This line:
if (bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr) != 0))
Shoud be:
if (bind(server, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) != 0)
first of all, forgive my code for being ugly. The tons of ideas I've been given to try to fix this code have jumbled it up after all the potential solutions that haven't worked. Basically, I'm coding a Hearthstone rip-off that reads in two .txt files with card information and battles them to see which player wins. The issue is that when I'm trying to save the player's name (the first line in the files), it saves the whole file instead of just the first line. When I have managed to fix that, the for loop used to save the information for the card objects (format: card name, card power, card health) does not get saved properly for some reason. Any help would be appreciated, I've been trying to fix this for two days and nothing has fully solved the problem. I'll attach the read in files first before the code.
Disclaimer: It's a lot of lines and I'm sorry about that. Also I think the problem could be that my Mac is not saving the .txt in a format that has the right line endings. I'm using XCode as my IDE. Thank you so much to whomever is willing to help!
File1:
The Innkeeper
3
Tunnel Trogg
1
3
Neptulon
7
7
Fire Elemental
6
5
File2:
Malfurion
3
Leper Gnome
2
1
Aviana
5
5
Cenarius
5
8
Main:
#include "Player.h"
using namespace std;
int main()
{
cout << "Please enter file name of the first player: " << endl;
string inFile = "";
getline(cin, inFile);
Player* p1 = new Player(inFile);
cout << "Now enter the file name of the second player: " << endl;
getline(cin, inFile);
Player* p2 = new Player(inFile);
p1->battle(*p2);
delete p1;
delete p2;
return 0;
}
Player Header:
#include "Card.h"
#include <fstream>
#ifndef Player_h
#define Player_h
using namespace std;
class Player
{
private:
string playerName;
int numCards;
Card ** cards;
int wins = 0;
public:
Player(std::string inFile);
void battle(Player p2);
Card* getCard(int counter);
~Player();
};
#endif /* Player_h */
Card Header:
#include <string>
#include <iostream>
#ifndef Card_h
#define Card_h
using namespace std;
class Card
{
public:
Card();
string getName();
int getPower();
int getHealth();
void setName(string newName);
void setPower(int newPower);
void setHealth(int newHealth);
Card* duel(Card&);
friend ostream& operator<<(ostream& o, Card& c);
friend bool operator==(Card& p1Card, Card& p2Card);
private:
string name;
int power;
int health;
};
#endif /* Card_h */
Player Source:
#include "Player.h"
using namespace std;
Player::Player(string inFile)
{
ifstream in(inFile, ios::in);\
if (!in)
{
cerr << "There was a problem opening the file. Sorry, try again!" << endl;
return;
}
getline(in, playerName);
cout << playerName << endl;
in>>numCards;
playerName = "";
numCards = 0;
cards = new Card* [numCards];
string tempName = "";
int tempPower = 0;
int tempHealth = 0;
for (int i = 0; i<numCards; i++)
{
in.ignore();
cards[i] = new Card();
getline(in, tempName);
cout << "in for loop: " << endl;
cout << tempName << ",";
cards[i]->setName(tempName);
in >> tempPower;
in.ignore();
cout << tempPower << ",";
cards[i]->setPower(tempPower);
in >> tempHealth;
cout << tempHealth << " done"<< endl;
cards[i]->setHealth(tempHealth);
}
}
void Player::battle(Player p2)
{
int draws = 0;
cout << "Let the battle begin!" << endl;
cout << numCards << endl;
if (wins > p2.wins)
{
cout << playerName << " wins over " << p2.playerName << ", " << wins << " to " << p2.wins;
if (draws == 0)
{
cout << " and no ties." << endl;
}
else
{
cout << " and " << draws << " ties." << endl;
}
}
else if (p2.wins > wins)
{
cout << p2.playerName << " wins over " << playerName << ", " << p2.wins << " to " << wins;
if (draws == 0)
{
cout << " and no ties." << endl;
}
else
{
cout << " and " << draws << " ties." << endl;
}
}
else if (p2.wins == wins)
{
cout << "It is a draw between " << playerName << " and " << p2.playerName << ", with " << wins << " for each and ";
if (draws == 0)
{
cout << "no ties." << endl;
}
else
{
cout << draws << " ties." << endl;
}
}
cout << "Here are the detailed results:" << endl;
for (int i = 0; i < numCards; i++)
{
cout << *cards[i] << " vs. " << *p2.cards[i] << " - ";
if (*cards[i] == *p2.cards[i])
{
cout << "It is a draw." << endl;
}
else if (cards[i]->duel(*p2.cards[i]) == NULL)
{
cout << "It is a draw." << endl;
}
else if (*cards[i]->duel(*p2.cards[i]) == *p2.cards[i])
{
cout << p2.cards[i]->getName() << "wins for " << p2.playerName << "." << endl;
}
else if (*cards[i]->duel(*p2.cards[i]) == *cards[i])
{
cout << cards[i]->getName() << "wins for " << playerName << "." << endl;
}
}
}
Player::~Player()
{
if (cards != NULL)
{
for (int i = 0; i < numCards; i++)
{
if (cards[i] != nullptr)
{
delete cards[i];
cards[i] = NULL;
}
};
}
}
Card Source:
#include "Card.h"
using namespace std;
Card::Card()
{
name = "";
power = 0;
health = 0;
}
string Card::getName()
{
return name;
}
int Card::getPower()
{
return power;
}
int Card::getHealth()
{
return health;
}
void Card::setName(string newName)
{
name = newName;
}
void Card::setPower(int newPower)
{
power = newPower;
}
void Card::setHealth(int newHealth)
{
health = newHealth;
}
Card* Card::duel(Card& otherCard)
{
if ((otherCard.getHealth() - this->getPower() <=0) && (getHealth() - otherCard.getPower() <= 0))
{
return NULL;
}
else if ((otherCard.getHealth() - this->getPower() >0) && (getHealth() - otherCard.getPower() >0))
{
return NULL;
}
else if (otherCard.getHealth() - this->getPower() <=0)
{
return this;
}
else if (this->getHealth() - otherCard.getPower() <=0)
{
return &otherCard;
}
return NULL;
}
ostream& operator<<(ostream& o, Card& c)
{
o << c.getName() << " (" << c.power << ", " << c.health << ") " << endl;
return o;
}
bool operator==(Card& p1Card, Card& p2Card)
{
if (p1Card.health == p2Card.health &&
p1Card.power == p2Card.power &&
p1Card.name == p2Card.name)
{
return true;
}
else
{
return false;
}
}
Your code is almost right. It can read the Player's name and the card numbers, but your codes showed below:
in>>numCards;
playerName = "";
numCards = 0;
cards = new Card* [numCards];
at first, it read the num of card and store it to numCards, it is right.
next, you clear the value of the numCards, then, you lost the num of the Card, so the codes followed it are executed with numCards == 0
You can just comment the line numCards = 0, and your code is executed right.
I wrote the following program to record the sound through soundcard in windows and print the PCM data from buffer of waveheader. But it gives only the data 32600-32700. Is the problem with my soundcard? I have used WAVE_MAPPER which automatically selects the source...Please help me
#include <Windows.h>
#include <MMSystem.h>
#include <iostream>
using namespace std;
int main(){
HWAVEIN microHandle;
WAVEHDR waveHeader;
MIXERCAPS mixerCaps;
WAVEFORMATEX format;
//HWAVEOUT hwo; // play
while (1){
const int NUMPTS = 44100 * 0.01; // 10 seconds
int sampleRate = 44100; //can get frequency from here
short int waveIn[NUMPTS]; // 'short int' is a 16-bit type; I request 16-bit samples below
// for 8-bit capture, you'd use 'unsigned char' or 'BYTE' 8-bit types
MMRESULT result = 0;
format.wFormatTag = WAVE_FORMAT_PCM; // simple, uncompressed format
format.wBitsPerSample = 8; // 16 for high quality, 8 for telephone-grade
format.nChannels = 1; // 1=mono, 2=stereo
format.nSamplesPerSec = sampleRate; // 22050
format.nAvgBytesPerSec = format.nSamplesPerSec*format.nChannels*format.wBitsPerSample / 8;
// = nSamplesPerSec * n.Channels * wBitsPerSample/8
format.nBlockAlign = format.nChannels*format.wBitsPerSample / 8;
// = n.Channels * wBitsPerSample/8
format.cbSize = 0;
result = waveInOpen(µHandle, WAVE_MAPPER, &format, 0L, 0L, WAVE_FORMAT_DIRECT);
cout << "checking step 1" << endl;
if (result)
{
cout << "Fail step 1" << endl;
cout << result << endl;
Sleep(10000);
return 0;
}
// Set up and prepare header for input
waveHeader.lpData = (LPSTR)waveIn;
waveHeader.dwBufferLength = NUMPTS;// *2;//why *2
waveHeader.dwBytesRecorded = 0;
waveHeader.dwUser = 0L;
waveHeader.dwFlags = 0L;
waveHeader.dwLoops = 0L;
waveInPrepareHeader(microHandle, &waveHeader, sizeof(WAVEHDR));
// Insert a wave input buffer
result = waveInAddBuffer(microHandle, &waveHeader, sizeof(WAVEHDR));
int NumOfMixers = mixerGetNumDevs();
cout << NumOfMixers << endl;
//cout<<(char*)mixerCaps.szPname<<endl;
//system("pause");
cout << "checking step 2" << endl;
if (result)
{
cout << "Fail step 2" << endl;
cout << result << endl;
Sleep(10000);
return 0;
}
//system("pause");
result = waveInStart(microHandle);
cout << "checking step 3......started recording..." << endl;
if (result)
{
cout << "Fail step 3" << endl;
cout << result << endl;
Sleep(10000);
return 0;
}
// Wait until finished recording
do { cout << "still"; } while (waveInUnprepareHeader(microHandle, &waveHeader, sizeof(WAVEHDR)) == WAVERR_STILLPLAYING);
waveInStop(microHandle);
waveInReset(microHandle);
//waveInUnprepareHeader(hwi, lpWaveHdr, sizeof(WAVEHDR));
waveInClose(microHandle);
//printing the buffer
for (int i = 0; i < waveHeader.dwBufferLength; i++)
{
if (waveIn[i] > 0)
cout << i << "\t" << waveIn[i] << endl;
}
}
system("pause");
//waveInClose(microHandle);
return 0;
}
I would be very grateful if someone could help me...
One obvious problem is that you're mixing the usage of 16 and 8 bits. You're buffer is defined as a 16-bit short. Notice your own comment:
short int waveIn[NUMPTS]; // 'short int' is a 16-bit type; I request 16-bit samples below
// for 8-bit capture, you'd use 'unsigned char' or 'BYTE' 8-bit types
Yet, when defining the audio format you are specifying 8 bits:
format.wBitsPerSample = 8; // 16 for high quality, 8 for telephone-grade
Either change format.wBitsPerSample = 16 or if you want 8 bit audio then do something like this:
unsigned char waveIn[NUMPTS];
...
format.wBitsPerSample = 8; // 16 for high quality, 8 for telephone-grade
//printing the buffer
for (int i = 0; i < waveHeader.dwBufferLength; i++)
{
cout << i << "\t" << (int)waveIn[i] << endl;
}
I am trying to record the audio at windows, here is my code. it works well for 8 bit, but it cannot work for 16 bit. Can anyone help me?
#include
#include
#include
#pragma comment(lib,"winmm.lib")
using namespace std;
int test(){
HWAVEIN microHandle;
WAVEHDR waveHeader;
MMRESULT result = 0;
WAVEFORMATEX waveformat;
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.wBitsPerSample=8;
waveformat.nSamplesPerSec=16000;//8000;
waveformat.nAvgBytesPerSec=waveformat.nSamplesPerSec*waveformat.nSamplesPerSec/8;
waveformat.nChannels=1;
waveformat.nBlockAlign=waveformat.nChannels*waveformat.wBitsPerSample/8;
waveformat.cbSize=0;
result = waveInOpen(µHandle, WAVE_MAPPER, &waveformat, 0L, 0L, CALLBACK_EVENT);
if (result)
{
cout << "Fail step 1" << endl;
cout << result << endl;
Sleep(10000);
return 0;
}
const int BUFSIZE = 16000*4;
char * buf = (char *)malloc(BUFSIZE);
// Set up and prepare header for input
waveHeader.lpData = (LPSTR)buf;
waveHeader.dwBufferLength = BUFSIZE;
waveHeader.dwBytesRecorded=0;
waveHeader.dwUser = 0L;
waveHeader.dwFlags = 0L;
waveHeader.dwLoops = 0L;
waveInPrepareHeader(microHandle, &waveHeader, sizeof(WAVEHDR));
// Insert a wave input buffer
result = waveInAddBuffer(microHandle, &waveHeader, sizeof(WAVEHDR));
if (result)
{
cout << "Fail step 2" << endl;
cout << result << endl;
Sleep(10000);
return 0;
}
result = waveInStart(microHandle);
if (result)
{
cout << "Fail step 3" << endl;
cout << result << endl;
Sleep(10000);
return 0;
}
// Wait until finished recording
do {} while (waveInUnprepareHeader(microHandle, &waveHeader, sizeof(WAVEHDR))==WAVERR_STILLPLAYING);
FILE *fp = fopen("output.pcm","w");
fwrite(buf,1,BUFSIZE,fp);
fclose(fp);
waveInClose(microHandle);
return 0;
}
void main()
{
test();
}
If I set the parameter waveformat.wBitsPerSample = 8, it can record the audio correctly,
but if i set it waveformat.wBitsPerSample = 16, it record the Noise!!!
Can anyone help me?
thanks.
it should bu FILE *fp = fopen("output.pcm","wb"); NOT FILE *fp = fopen("output.pcm","w");