📄 in_mp4.cpp
字号:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <tchar.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#ifndef _WIN32_WCE
#include <mmsystem.h>
#endif
#include "mapplugin.h"
#include "in_mp4.h"
extern "C" {
#include "utils.h"
}
BOOL GetId3TagV1(FILE* fp, MAP_PLUGIN_FILETAG* pTag);
BOOL GetId3TagV2(FILE* fp, MAP_PLUGIN_FILETAG* pTag);
state mp4state = {0};
uint8_t* leftoutbuf = NULL;
int leftoutbuflen = 0;
void flushleftbuf()
{
if (leftoutbuf) {
free(leftoutbuf);
leftoutbuf = NULL;
}
leftoutbuf = 0;
}
uint32_t read_callback(void *user_data, void *buffer, uint32_t length)
{
return fread(buffer, 1, length, (FILE*)user_data);
}
uint32_t seek_callback(void *user_data, uint64_t position)
{
return fseek((FILE*)user_data, (uint32_t)position, SEEK_SET);
}
uint32_t write_callback(void *user_data, void *buffer, uint32_t length)
{
return fwrite(buffer, 1, length, (FILE*)user_data);
}
uint32_t truncate_callback(void *user_data)
{
//_chsize(fileno((FILE*)user_data), ftell((FILE*)user_data));
//return 1;
// update tag future is not supported!
return 0;
}
int skip_id3v2_tag()
{
unsigned char buf[10];
int bread, tagsize = 0;
bread = fread(buf, 1, 10, mp4state.aacfile);
if (bread != 10) return -1;
if (!memcmp(buf, "ID3", 3))
{
/* high bit is not used */
tagsize = (buf[6] << 21) | (buf[7] << 14) | (buf[8] << 7) | (buf[9] << 0);
tagsize += 10;
fseek(mp4state.aacfile, tagsize, SEEK_SET);
} else {
fseek(mp4state.aacfile, 0, SEEK_SET);
}
return tagsize;
}
int fill_buffer(state *st)
{
int bread;
if (st->m_aac_bytes_consumed > 0)
{
if (st->m_aac_bytes_into_buffer)
{
memmove((void*)st->m_aac_buffer, (void*)(st->m_aac_buffer + st->m_aac_bytes_consumed),
st->m_aac_bytes_into_buffer*sizeof(unsigned char));
}
if (!st->m_at_eof)
{
bread = fread((void*)(st->m_aac_buffer + st->m_aac_bytes_into_buffer),
1, st->m_aac_bytes_consumed, st->aacfile);
if (bread != st->m_aac_bytes_consumed)
st->m_at_eof = 1;
st->m_aac_bytes_into_buffer += bread;
}
st->m_aac_bytes_consumed = 0;
if (st->m_aac_bytes_into_buffer > 3)
{
if (memcmp(st->m_aac_buffer, "TAG", 3) == 0)
st->m_aac_bytes_into_buffer = 0;
}
if (st->m_aac_bytes_into_buffer > 11)
{
if (memcmp(st->m_aac_buffer, "LYRICSBEGIN", 11) == 0)
st->m_aac_bytes_into_buffer = 0;
}
if (st->m_aac_bytes_into_buffer > 8)
{
if (memcmp(st->m_aac_buffer, "APETAGEX", 8) == 0)
st->m_aac_bytes_into_buffer = 0;
}
}
return 1;
}
void advance_buffer(state *st, int bytes)
{
st->m_file_offset += bytes;
st->m_aac_bytes_consumed = bytes;
st->m_aac_bytes_into_buffer -= bytes;
}
int file_length(FILE *f)
{
long end = 0;
long cur = ftell(f);
fseek(f, 0, SEEK_END);
end = ftell(f);
fseek(f, cur, SEEK_SET);
return end;
}
int is_adts_header(unsigned char* buf, int length)
{
int frame_length;
if (length < 8)
return 0;
// check syncword
if (!((buf[0] == 0xFF)&&((buf[1] & 0xF6) == 0xF0)))
return 0;
// check samplerate
if ((buf[2]&0x3c)>>2 > 0x11)
return 0;
return 1;
}
int is_adif_header(unsigned char* buf, int length)
{
if (buf[0] == 'A' && buf[1] == 'D' && buf[2] == 'I' && buf[3] == 'F')
return 1;
return 0;
}
int is_aac_frame_header(unsigned char* buf, int length)
{
if (is_adts_header(buf, length))
return 1;
if (is_adif_header(buf, length))
return 1;
return 0;
}
#if 0
// too late!!
int adts_parse(state *st, __int64 *bitrate, double *length)
{
static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000};
int frames, frame_length;
int t_framelength = 0;
int samplerate;
double frames_per_sec, bytes_per_frame;
/* Read all frames to ensure correct time and bitrate */
for (frames = 0; /* */; frames++)
{
fill_buffer(st);
if (st->m_aac_bytes_into_buffer > 7)
{
/* check syncword */
if (!((st->m_aac_buffer[0] == 0xFF)&&((st->m_aac_buffer[1] & 0xF6) == 0xF0)))
break;
st->m_tail->offset = st->m_file_offset;
st->m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
st->m_tail = st->m_tail->next;
st->m_tail->next = NULL;
if (frames == 0)
samplerate = sample_rates[(st->m_aac_buffer[2]&0x3c)>>2];
frame_length = ((((unsigned int)st->m_aac_buffer[3] & 0x3)) << 11)
| (((unsigned int)st->m_aac_buffer[4]) << 3) | (st->m_aac_buffer[5] >> 5);
t_framelength += frame_length;
if (frame_length > st->m_aac_bytes_into_buffer)
break;
advance_buffer(st, frame_length);
} else {
break;
}
}
frames_per_sec = (double)samplerate/1024.0;
if (frames != 0)
bytes_per_frame = (double)t_framelength/(double)(frames*1000);
else
bytes_per_frame = 0;
*bitrate = (__int64)(8. * bytes_per_frame * frames_per_sec + 0.5);
if (frames_per_sec != 0)
*length = (double)frames/frames_per_sec;
else
*length = 1;
return 1;
}
#else
// fast! (easy!)
int adts_parse(state *st, __int64 *bitrate, double *length)
{
static int sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000};
int frames, frame_length;
int t_framelength = 0;
int samplerate;
double frames_per_sec, bytes_per_frame;
double filelength = (double)file_length(mp4state.aacfile);
#define MAX_AAC_PARSE_HEADER 128
/* Read all frames to ensure correct time and bitrate */
for (frames = 0; frames < MAX_AAC_PARSE_HEADER; frames++)
{
fill_buffer(st);
if (st->m_aac_bytes_into_buffer > 7)
{
/* check syncword */
if (!((st->m_aac_buffer[0] == 0xFF)&&((st->m_aac_buffer[1] & 0xF6) == 0xF0)))
break;
if (frames == 0)
samplerate = sample_rates[(st->m_aac_buffer[2]&0x3c)>>2];
frame_length = ((((unsigned int)st->m_aac_buffer[3] & 0x3)) << 11)
| (((unsigned int)st->m_aac_buffer[4]) << 3) | (st->m_aac_buffer[5] >> 5);
t_framelength += frame_length;
if (frame_length > st->m_aac_bytes_into_buffer)
break;
advance_buffer(st, frame_length);
} else {
break;
}
}
frames_per_sec = (double)samplerate/1024.0;
if (frames != 0)
bytes_per_frame = (double)t_framelength/(double)(frames*1000);
else
bytes_per_frame = 0;
*bitrate = (__int64)(8. * bytes_per_frame * frames_per_sec);
if (frames_per_sec != 0)
*length = filelength / ((8. * bytes_per_frame * frames_per_sec) * 1000 / 8);
else
*length = 1;
return 1;
}
#endif
void *decode_aac_frame(state *st, NeAACDecFrameInfo *frameInfo)
{
void *sample_buffer = NULL;
do
{
fill_buffer(st);
if (st->m_aac_bytes_into_buffer != 0)
{
sample_buffer = NeAACDecDecode(st->hDecoder, frameInfo,
st->m_aac_buffer, st->m_aac_bytes_into_buffer);
if (st->m_header_type != 1)
{
if (st->last_offset < st->m_file_offset)
{
st->m_tail->offset = st->m_file_offset;
st->m_tail->next = (struct seek_list*)malloc(sizeof(struct seek_list));
st->m_tail = st->m_tail->next;
st->m_tail->next = NULL;
st->last_offset = st->m_file_offset;
}
}
advance_buffer(st, frameInfo->bytesconsumed);
} else {
break;
}
} while (!frameInfo->samples && !frameInfo->error);
return sample_buffer;
}
#if 0
// too late!!
int aac_seek(state *st, double seconds)
{
int i, frames;
int bread;
struct seek_list *target = st->m_head;
if (1 /*can_seek*/ && ((st->m_header_type == 1) || (seconds < st->cur_pos_sec)))
{
frames = (int)(seconds*((double)st->samplerate/(double)st->framesize) + 0.5);
for (i = 0; i < frames; i++)
{
if (target->next)
target = target->next;
else
return 0;
}
if (target->offset == 0 && frames > 0)
return 0;
fseek(st->aacfile, st->m_tagsize + target->offset, SEEK_SET);
st->m_file_offset = target->offset + st->m_tagsize;
bread = fread(st->m_aac_buffer, 1, 768*6, st->aacfile);
if (bread != 768*6)
st->m_at_eof = 1;
else
st->m_at_eof = 0;
st->m_aac_bytes_into_buffer = bread;
st->m_aac_bytes_consumed = 0;
st->m_file_offset += bread;
NeAACDecPostSeekReset(st->hDecoder, -1);
return 1;
} else {
if (seconds > st->cur_pos_sec)
{
NeAACDecFrameInfo frameInfo;
frames = (int)((seconds - st->cur_pos_sec)*((double)st->samplerate/(double)st->framesize));
if (frames > 0)
{
for (i = 0; i < frames; i++)
{
memset(&frameInfo, 0, sizeof(NeAACDecFrameInfo));
decode_aac_frame(st, &frameInfo);
if (frameInfo.error || (st->m_aac_bytes_into_buffer == 0))
{
return 0;
}
}
}
NeAACDecPostSeekReset(st->hDecoder, -1);
}
return 1;
}
}
#else
int aac_seek(state *st, double seconds)
{
double filelength = file_length(st->aacfile);
double offset;
unsigned long samplerate;
unsigned char channels;
NeAACDecFrameInfo frameInfo = {0};
//seconds = 63.073000000000000;
offset = (filelength - st->m_tagsize) / (st->m_length / 1000) * seconds;
offset += st->m_tagsize;
fseek(st->aacfile, offset, SEEK_SET);
st->m_file_offset = offset;
st->m_at_eof = 0;
st->m_aac_bytes_consumed = 768*6;
st->m_aac_bytes_into_buffer = 0;
fill_buffer(st);
NeAACDecPostSeekReset(st->hDecoder, -1);
while (!st->m_at_eof && st->m_aac_bytes_into_buffer) {
if (is_aac_frame_header(st->m_aac_buffer, st->m_aac_bytes_into_buffer)) {
memset(&frameInfo, 0, sizeof(frameInfo));
NeAACDecDecode(mp4state.hDecoder, &frameInfo, mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer);
if (frameInfo.error == 0) {
break;
}
}
advance_buffer(st, 1);
fill_buffer(st);
}
if (st->m_at_eof || !st->m_aac_bytes_into_buffer)
return 0;
NeAACDecPostSeekReset(st->hDecoder, -1);
return 1;
}
#endif
int isourfile(TCHAR *fn)
{
if (!_tcsicmp(fn + _tcslen(fn) - 4, _T(".MP4")))
return 1;
if (!_tcsicmp(fn + _tcslen(fn) - 4, _T(".M4A")))
return 1;
if (!_tcsicmp(fn + _tcslen(fn) - 4, _T(".AAC")))
return 1;
if (!_tcsicmp(fn + _tcslen(fn) - 4, _T(".3GP")))
return 1;
return 0;
}
static void remap_channels(unsigned char *data, unsigned int samples, unsigned int bps)
{
unsigned int i;
switch (bps)
{
case 8:
{
unsigned char r1, r2, r3, r4, r5, r6;
for (i = 0; i < samples; i += 6)
{
r1 = data[i];
r2 = data[i+1];
r3 = data[i+2];
r4 = data[i+3];
r5 = data[i+4];
r6 = data[i+5];
data[i] = r2;
data[i+1] = r3;
data[i+2] = r1;
data[i+3] = r6;
data[i+4] = r4;
data[i+5] = r5;
}
}
break;
case 16:
default:
{
unsigned short r1, r2, r3, r4, r5, r6;
unsigned short *sample_buffer = (unsigned short *)data;
for (i = 0; i < samples; i += 6)
{
r1 = sample_buffer[i];
r2 = sample_buffer[i+1];
r3 = sample_buffer[i+2];
r4 = sample_buffer[i+3];
r5 = sample_buffer[i+4];
r6 = sample_buffer[i+5];
sample_buffer[i] = r2;
sample_buffer[i+1] = r3;
sample_buffer[i+2] = r1;
sample_buffer[i+3] = r6;
sample_buffer[i+4] = r4;
sample_buffer[i+5] = r5;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -