void WriteData()
{
while (isRunning_) {
AVFormatContext *inputContext = avformat_alloc_context();
std::string inputFile = "/data/360p.mp4";
// std::string outFile = "/data/ffmpeg.txt";
// FILE *fp = fopen(outFile.c_str(), "wb");
AVPacket packet;
AVCodec *codec = nullptr;
AVCodecContext *codecContext = nullptr;
struct SwrContext *convertContext = nullptr;
AVSampleFormat in_sample_fmt;
AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;
int in_sample_rate;
int out_sample_rate = 48000;
uint64_t in_channel_layout;
uint64_t out_channel_layout = AV_CH_LAYOUT_MONO;
int out_channel_nb = 0;
uint8_t *buffer = nullptr;
int video_stream = -1;
int audio_stream = -1;
LOGD("write file in");
int ret = 0;
if ((ret = avformat_open_input(&inputContext, inputFile.c_str(), nullptr, nullptr)) != 0) {
LOGE("ffmpeg open file failed, %s", av_err2str(ret));
break;
}
ret = avformat_find_stream_info(inputContext, nullptr);
video_stream = av_find_best_stream(inputContext, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
audio_stream = av_find_best_stream(inputContext, AVMEDIA_TYPE_AUDIO, -1, -1, nullptr, 0);
if (video_stream < 0 && audio_stream < 0) {
LOGE("find video && audio stream error");
avformat_close_input(&inputContext);
break;
}
if (audio_stream >= 0) {
av_dump_format(inputContext, audio_stream, inputFile.c_str(), 0);
codec = avcodec_find_decoder(inputContext->streams[audio_stream]->codecpar->codec_id);
codecContext = avcodec_alloc_context3(codec);
avcodec_parameters_to_context(codecContext, inputContext->streams[audio_stream]->codecpar);
if (avcodec_open2(codecContext, codec, nullptr) < 0) {
LOGE("open codec error");
avformat_close_input(&inputContext);
break;
}
convertContext = swr_alloc();
in_sample_fmt = codecContext->sample_fmt;
in_sample_rate = codecContext->sample_rate;
in_channel_layout = codecContext->channel_layout;
convertContext = swr_alloc_set_opts(convertContext, out_channel_layout, out_sample_fmt, out_sample_rate,
in_channel_layout, in_sample_fmt, in_sample_rate, 0, nullptr);
swr_init(convertContext);
out_channel_nb = av_get_channel_layout_nb_channels(out_channel_layout);
buffer = (uint8_t *)av_malloc(2 * 48000);
}
if (video_stream >= 0) {
av_dump_format(inputContext, video_stream, inputFile.c_str(), 0);
}
double vfps = 0.0;
if (inputContext->streams[video_stream]->avg_frame_rate.den == 0 ||
(inputContext->streams[video_stream]->avg_frame_rate.num == 0 &&
inputContext->streams[video_stream]->avg_frame_rate.den == 1)) {
vfps = inputContext->streams[video_stream]->r_frame_rate.num /
inputContext->streams[video_stream]->r_frame_rate.den;
} else {
vfps = inputContext->streams[video_stream]->avg_frame_rate.num /
inputContext->streams[video_stream]->avg_frame_rate.den;
}
double afps = (48000 * 2 * 16 / 8) / (1024 * 2 * 16 / 8.0); // aac
LOGD("vfpr: %lf, afps: %lf", vfps, afps);
av_init_packet(&packet);
packet.data = nullptr;
packet.size = 0;
bool reading = true;
int32_t keyCount = 0;
LOGD("write file start");
while (reading) {
static std::chrono::time_point timeStart = std::chrono::system_clock::now();
int error = av_read_frame(inputContext, &packet);
if (error == AVERROR_EOF) {
// auto stream = inputContext->streams[video_stream];
// avio_seek(inputContext->pb, 0, SEEK_SET); // io context set to 0
// avformat_seek_file(inputContext, video_stream, 0, 0, stream->duration, 0);
// continue;
reading = false; // 取消重复读取
break;
} else if (error < 0) {
break;
}
if (audio_stream == packet.stream_index) {
AVFrame *frame = av_frame_alloc();
ret = avcodec_send_packet(codecContext, &packet);
while (ret >= 0) {
ret = avcodec_receive_frame(codecContext, frame);
if (ret < 0) {
break;
}
swr_convert(convertContext, &buffer, 2 * 48000, (const uint8_t **)frame->data,
frame->nb_samples);
int totalSize =
av_samples_get_buffer_size(nullptr, out_channel_nb, frame->nb_samples, out_sample_fmt,
0);
(void)totalSize;
fwrite(buffer, 1, totalSize, fp);
// ++ts_;
++writeAcount_;
av_frame_unref(frame);
}
auto timeStamp =
timeStart + std::chrono::microseconds(1000000 * 1000 / int(afps * 1000) * writeAcount_);
std::this_thread::sleep_until(timeStamp);
} else if (video_stream == packet.stream_index) {
unsigned char *pData = packet.data; // frame data
unsigned char *pEnd = nullptr;
int dataSize = packet.size;
int curSize = 0;
unsigned char nalHeader, nalType;
AVPacket *outPacket = av_packet_alloc();
pEnd = pData + dataSize;
LOGD("packet size: %d, flag: %d, pts: %lld", packet.size,
packet.flags, packet.pts);
while (curSize < dataSize) {
AVPacket spsppsPacket;
spsppsPacket.data = nullptr;
spsppsPacket.size = 0;
int naluSize = 0;
if (pEnd - pData < 4) {
break;
}
for (int i = 0; i < 4; ++i) {
naluSize <<= 8;
naluSize |= pData[i];
// LOGD("naluSize: %d, pData[i]: %d, %02X", naluSize, pData[i],
// pData[i]);
}
pData += 4;
curSize += 4;
if (naluSize > (pEnd - pData + 1) || naluSize <= 0) {
LOGD("nalusize error, real size: %d, naluSize: %d",
pEnd - pData + 1, naluSize);
break;
}
nalHeader = *pData;
nalType = nalHeader & 0x1F;
LOGD("nalType: %u, flag: %d", nalType, packet.flags);
if (nalType == 6) {
pData += naluSize;
curSize += naluSize;
continue;
} else if (nalType == 5) {
// key frame
h264_extradata_to_annexb(
inputContext->streams[packet.stream_index]->codecpar->extradata,
inputContext->streams[packet.stream_index]->codecpar->extradata_size, &spsppsPacket,
AV_INPUT_BUFFER_PADDING_SIZE);
if (alloc_and_copy(outPacket, spsppsPacket.data, spsppsPacket.size, pData, naluSize) < 0) {
av_packet_free(&outPacket);
if (spsppsPacket.data) {
free(spsppsPacket.data);
spsppsPacket.data = nullptr;
}
break;
}
} else {
if (alloc_and_copy(outPacket, nullptr, 0, pData, naluSize) < 0) {
av_packet_free(&outPacket);
if (spsppsPacket.data) {
free(spsppsPacket.data);
spsppsPacket.data = nullptr;
}
break;
}
}
if (spsppsPacket.data) {
free(spsppsPacket.data);
spsppsPacket.data = nullptr;
}
curSize += naluSize;
LOGD("goto next, diffsize: %d", packet.size - outPacket->size);
}
// ++ts_;
// if (outPacket->isKey) {
// ++keyCount;
// LOGD("write key frame: %d, pts: %lld", keyCount, pts);
// }
++writeVcount_;
av_packet_unref(outPacket);
auto timeStamp =
timeStart + std::chrono::microseconds(1000000 * 1000 / int(vfps * 1000) * writeVcount_);
std::this_thread::sleep_until(timeStamp); // 使用sleep_until控制时间
}
av_packet_unref(&packet);
}
LOGD("write file done, write audio: %u, write video: %u, keyCount: %d",
writeAcount_, writeVcount_, keyCount);
if (buffer != nullptr) {
free(buffer);
}
if (codecContext != nullptr) {
avcodec_close(codecContext);
}
avformat_close_input(&inputContext);
// fclose(fp);
break;
}
}