#if (FILE_FORMAT_AVI) #include #include #include #if !defined(BBEXTRACT) #include #include "rm_constants.h" #if (APPLICATION_PROFILE) #include #include #endif #endif //#if !defined(BBEXTRACT) #include "rm_format_avi.h" extern "C" { #include "fileio.h" } // 참조: https://github.com/masayukig/jpegtoavi/blob/master/aviformat.txt // http://telnet.or.kr/directx/htm/avirifffilereference.htm // http://blog.naver.com/PostView.nhn?blogId=shlee7708&logNo=120121689464 <- 제일 편함!! //static int skip_chunk(FILE *in) //{ //char chunk_id[5]; //int chunk_size; //int end_of_chunk; // read_chars(_file,chunk_id,4); // chunk_size=read_long(_file); // printf("Uknown Chunk at %d\n",(int)ftell(_file)); // printf("-------------------------------\n");q // printf(" chunk_id: %s\n",chunk_id); // printf(" chunk_size: %d\n",chunk_size); // printf("\n"); // end_of_chunk=ftell(_file)+chunk_size; // if ((end_of_chunk%4)!=0) // { // end_of_chunk=end_of_chunk+(4-(end_of_chunk%4)); // } // RMfseek(_file,end_of_chunk,SEEK_SET); // return 0; //} //AVIRiff(RMfile in,bool durationOnly = false); AVIRiff::AVIRiff(RMfile in,VideoReadMode mode, VideoPreInfo* info) { _readMode = mode; _preInfo = info; #if (SENSOR_AVI_SUBTITLE) subtitles = NULL; #endif if(_preInfo != NULL) { _preInfo->bDuration = false; _preInfo->duration = 0; #if (CHECK_VIDEO_BITRATE) _preInfo->movSize = 0; _preInfo->bMOVSize = false; #endif _preInfo->width = 0; _preInfo->height = 0; } _isValid = false; _file = in; _videoStreamCount = 0; #if (AVI_CHUNHO_SENSOR_FORMAT_1) _gps_buffer = NULL; _sensor_buffer = NULL; _gps_buffer_size = 0; _sensor_buffer_size = 0; #endif parse_riff(); } AVIRiff::~AVIRiff() { for(int i=0;i<_videoStreamCount;i++) { if(_videoStreamFormat[i].palette != NULL) { free(_videoStreamFormat[i].palette); } } #if (AVI_CHUNHO_SENSOR_FORMAT_1) if(_gps_buffer != NULL) { free(_gps_buffer); } if(_sensor_buffer != NULL) { free(_sensor_buffer); } #endif #if (SENSOR_AVI_SUBTITLE) if(subtitles != NULL) { for(int i=0;isize();i++) { free(subtitles->at(i)); } delete subtitles; subtitles = NULL; } #endif } int AVIRiff::hex_dump_chunk(int chunk_len) { #if (USE_AVI_DUMP) char chars[17]; int ch,n; chars[16]=0; int line = 0; for (n=0; n=' ' && ch<=126) { chars[n%16]=ch; } else { chars[n%16]='.'; } } if ((n%16)!=0) { for (ch=n%16; ch<16; ch++) { printf(" "); } } printf("%s\n", chars); #else #if !defined(BBEXTRACT) Q_UNUSED(chunk_len); #endif // #if !defined(BBEXTRACT) #endif return 0; } #if (DEBUG_AVI_FORMAT) int AVIRiff::parse_idx1(int chunk_len) { index_entry_t index_entry; int t; printf(" IDX1\n"); printf(" -------------------------------\n"); printf(" ckid dwFlags dwChunkOffset dwChunkLength\n"); for (t=0; tTimeBetweenFrames=read_long(_file); // AVI TYPE 1 = 0 avi_header->MaximumDataRate=read_long(_file); avi_header->PaddingGranularity=read_long(_file); avi_header->Flags=read_long(_file); avi_header->TotalNumberOfFrames=read_long(_file); avi_header->NumberOfInitialFrames=read_long(_file); avi_header->NumberOfStreams=read_long(_file); avi_header->SuggestedBufferSize=read_long(_file); avi_header->Width=read_long(_file); avi_header->Height=read_long(_file); avi_header->TimeScale=read_long(_file); avi_header->DataRate=read_long(_file); avi_header->StartTime=read_long(_file); avi_header->DataLength=read_long(_file); if(_preInfo != NULL) { _preInfo->width = avi_header->Width; _preInfo->height = avi_header->Height; } #if (DEBUG_AVI_HEADER) printf(" offset=0x%lx\n",offset); printf(" TimeBetweenFrames: %d\n",avi_header->TimeBetweenFrames); printf(" MaximumDataRate: %d\n",avi_header->MaximumDataRate); printf(" PaddingGranularity: %d\n",avi_header->PaddingGranularity); printf(" Flags: %d\n",avi_header->Flags); printf(" TotalNumberOfFrames: %d\n",avi_header->TotalNumberOfFrames); printf(" NumberOfInitialFrames: %d\n",avi_header->NumberOfInitialFrames); printf(" NumberOfStreams: %d\n",avi_header->NumberOfStreams); printf(" SuggestedBufferSize: %d\n",avi_header->SuggestedBufferSize); printf(" Width: %d\n",avi_header->Width); printf(" Height: %d\n",avi_header->Height); printf(" TimeScale: %d\n",avi_header->TimeScale); printf(" DataRate: %d\n",avi_header->DataRate); printf(" StartTime: %d\n",avi_header->StartTime); printf(" DataLength: %d\n",avi_header->DataLength); fflush(stdout); #endif return 0; } void AVIRiff::print_data_handler(unsigned char *handler) { int t; for (t=0; t<4; t++) { if ((handler[t]>='a' && handler[t]<='z') || (handler[t]>='A' && handler[t]<='Z') || (handler[t]>='0' && handler[t]<='9')) { printf("%c",handler[t]); } else { printf("[0x%02x]",handler[t]); } } } int AVIRiff::read_stream_header(stream_header_t *stream_header) { #if (DEBUG_AVI_STREAM_HEADER) long offset=ftell(_file); #endif read_chars(_file,stream_header->DataType,4); read_chars(_file,stream_header->DataHandler,4); stream_header->Flags=read_long(_file); stream_header->Priority=read_long(_file); stream_header->InitialFrames=read_long(_file); stream_header->TimeScale=read_long(_file); stream_header->DataRate=read_long(_file); stream_header->StartTime=read_long(_file); stream_header->DataLength=read_long(_file); stream_header->SuggestedBufferSize=read_long(_file); stream_header->Quality=read_long(_file); stream_header->SampleSize=read_long(_file); if(_preInfo != NULL) { if(_preInfo->duration == 0 && stream_header->TimeScale != 0) { _preInfo->bDuration = true; _preInfo->duration = (unsigned int)(((double)(stream_header->TimeScale * 1000) / (double)stream_header->DataRate) * (double)stream_header->DataLength); } } #if (DEBUG_AVI_STREAM_HEADER) printf("------------------------------------------------------------\n"); printf(" offset=0x%lx\n",offset); printf(" DataType: %s\n",stream_header->DataType); printf(" DataHandler: "); print_data_handler((unsigned char *)stream_header->DataHandler); printf("\n"); printf(" Flags: %d\n",stream_header->Flags); printf(" Priority: %d\n",stream_header->Priority); printf(" InitialFrames: %d\n",stream_header->InitialFrames); printf(" TimeScale: %d\n",stream_header->TimeScale); printf(" DataRate: %d\n",stream_header->DataRate); printf(" StartTime: %d\n",stream_header->StartTime); printf(" DataLength: %d\n",stream_header->DataLength); printf(" SuggestedBufferSize: %d\n",stream_header->SuggestedBufferSize); printf(" Quality: %d\n",stream_header->Quality); printf(" SampleSize: %d\n",stream_header->SampleSize); fflush(stdout); #endif return 0; } int AVIRiff::read_stream_format(stream_format_t *stream_format) { int t,r,g,b; #if (DEBUG_AVI_FORMAT) long offset=ftell(_file); #endif stream_format->header_size=read_long(_file); stream_format->image_width=read_long(_file); stream_format->image_height=read_long(_file); stream_format->number_of_planes=read_word(_file); stream_format->bits_per_pixel=read_word(_file); stream_format->compression_type=read_long(_file); stream_format->image_size_in_bytes=read_long(_file); stream_format->x_pels_per_meter=read_long(_file); stream_format->y_pels_per_meter=read_long(_file); stream_format->colors_used=read_long(_file); stream_format->colors_important=read_long(_file); stream_format->palette=0; if (stream_format->colors_important!=0) { stream_format->palette= (int*) malloc(stream_format->colors_important*sizeof(int)); for (t=0; tcolors_important; t++) { b=RMgetc(_file); g=RMgetc(_file); r=RMgetc(_file); stream_format->palette[t]=(r<<16)+(g<<8)+b; } } #if (DEBUG_AVI_FORMAT) printf(" offset=0x%lx\n",offset); printf(" header_size: %d\n",stream_format->header_size); printf(" image_width: %d\n",stream_format->image_width); printf(" image_height: %d\n",stream_format->image_height); printf(" number_of_planes: %d\n",stream_format->number_of_planes); printf(" bits_per_pixel: %d\n",stream_format->bits_per_pixel); printf(" compression_type: %04x (%c%c%c%c)\n",stream_format->compression_type, ((stream_format->compression_type)&255), ((stream_format->compression_type>>8)&255), ((stream_format->compression_type>>16)&255), ((stream_format->compression_type>>24)&255)); printf(" image_size_in_bytes: %d\n",stream_format->image_size_in_bytes); printf(" x_pels_per_meter: %d\n",stream_format->x_pels_per_meter); printf(" y_pels_per_meter: %d\n",stream_format->y_pels_per_meter); printf(" colors_used: %d\n",stream_format->colors_used); printf(" colors_important: %d\n",stream_format->colors_important); fflush(stdout); #endif return 0; } int AVIRiff::read_stream_format_auds(stream_format_auds_t *stream_format) { #if (DEBUG_AVI_FORMAT) long offset=RMftell(_file); #endif stream_format->format=read_word(_file); stream_format->channels=read_word(_file); stream_format->samples_per_second=read_long(_file); stream_format->bytes_per_second=read_long(_file); #if (DEBUG_AVI_FORMAT) int block_align=read_word(_file); #endif stream_format->block_size_of_data=read_word(_file); stream_format->bits_per_sample=read_word(_file); //stream_format->extended_size=read_word(_file); #if (DEBUG_AVI_FORMAT) printf(" offset=0x%lx\n",offset); printf(" format: %d\n",stream_format->format); printf(" channels: %d\n",stream_format->channels); printf(" samples_per_second: %d\n",stream_format->samples_per_second); printf(" bytes_per_second: %d\n",stream_format->bytes_per_second); printf(" block_align: %d\n",block_align); printf(" block_size_of_data: %d\n",stream_format->block_size_of_data); printf(" bits_per_sample: %d\n",stream_format->bits_per_sample); #endif return 0; } int AVIRiff::parse_hdrl_list() { // stream_format_auds_t stream_format_auds; // stream_header_t stream_header_auds; char chunk_id[5]; int chunk_size; char chunk_type[5]; int end_of_chunk; int next_chunk; //long offset=RMftell(_file); AVI_STREAM_TYPE stream_type = UNDEFINED_STREAM; read_chars(_file,chunk_id,4); chunk_size=read_long(_file); read_chars(_file,chunk_type,4); #if (DEBUG_AVI_FORMAT) printf(" AVI Header LIST (id=%s size=%d type=%s offset=0x%lx)\n",chunk_id,chunk_size,chunk_type,offset); printf(" {\n"); #endif end_of_chunk=RMftell(_file)+chunk_size-4; if ((end_of_chunk%4)!=0) { //printf("Adjusting end of chunk %d\n", end_of_chunk); //end_of_chunk=end_of_chunk+(4-(end_of_chunk%4)); //printf("Adjusting end of chunk %d\n", end_of_chunk); } if (strcmp(chunk_id,"JUNK")==0) { RMfseek(_file,end_of_chunk,SEEK_SET); #if (DEBUG_AVI_FORMAT) printf(" }\n"); #endif return 0; } while (RMftell(_file)(); } char* buffer = (char*)malloc(chunkSize + 1); memset(buffer,0,chunkSize + 1); RMfread(buffer,chunkSize,1,_file); //qInfo() << buffer; //QString str = QString(buffer); subtitles->append(buffer); //free(buffer); return 0; } #endif int AVIRiff::parse_movi_list(unsigned int size) { #if (APPLICATION_PROFILE) QElapsedTimer timer; timer.start(); #endif char chunk_id[5] = {0,}; long chunk_size; long end_of_chunk; long offset=RMftell(_file); #if (DEBUG_AVI_MOVI) printf(" AVI MOVI Chunk (id=%s size=%d offset=0x%lx)\n",chunk_id,chunk_size,offset); printf(" {\n"); fflush(stdout); #endif //int txtCount = 0; while(RMftell(_file)< offset+(long)size-4) { read_chars(_file,chunk_id,4); // 4 byte chunk_size=read_long(_file); // 4 byte // pack 하지 않는다.. 다음 chunk 의 chunk_id + size 제외하고 이동 end_of_chunk= RMftell(_file) + chunk_size; // H265 AVI 는 2 BYTE pack 되어 있음.. if ((end_of_chunk % 2) == 1) { end_of_chunk += 1; } if(chunk_id[2] == 't' && chunk_id[3] == 'x') { #if (SENSOR_AVI_SUBTITLE) add_subtitle(chunk_size); #endif #if (DEBUG_AVI_MOVI) printf(" MOVI TXT (id(%04d)=%s size=%d offset=%ld)\n",txtCount++,chunk_id,chunk_size,ftell(_file)); // hex_dump_chunk(chunk_size); fflush(stdout); #endif } else { // 이후 NAL SEI 처리 기능 추가 } RMfseek(_file,end_of_chunk,SEEK_SET); } #if (DEBUG_AVI_MOVI) printf(" }\n"); fflush(stdout); #endif #if (APPLICATION_PROFILE) qInfo () << "Elapsed Time(parse_movi_list):" << timer.elapsed() << " msec" << " count:" << txtCount; #endif return 0; } //int AVIRiff::parse_hdrl(stream_format_t *stream_format, unsigned int size) int AVIRiff::parse_hdrl(unsigned int size) { char chunk_id[5]; long chunk_size; long end_of_chunk; long offset=RMftell(_file); read_chars(_file,chunk_id,4); chunk_size=read_long(_file); #if (DEBUG_AVI_FORMAT) printf(" AVI Header Chunk (id=%s size=%d offset=0x%lx)\n",chunk_id,chunk_size,offset); printf(" {\n"); #endif end_of_chunk=RMftell(_file)+chunk_size; if ((end_of_chunk%4)!=0) // 4BYTE PACK { end_of_chunk=end_of_chunk+(4-(end_of_chunk%4)); } read_avi_header(); // 메인 헤더 읽기 #if (DEBUG_AVI_FORMAT) printf(" }\n"); #endif while(RMftell(_file) 0) { //qInfo() << "gsen offset:" << offsetStr; _sensor_buffer_size = chunk_size; _sensor_buffer = (uint8_t*)malloc(chunk_size); RMfread(_sensor_buffer,_sensor_buffer_size,1,_file); b_sensor_read = true; } } // 깨진 데이터는 1 BYTE 씩 탐색 else if(chunk_size < 0 || (strcasecmp("IDIT",chunk_id) != 0 && strcasecmp("gpsa",chunk_id) != 0 && strcasecmp("gsea",chunk_id) != 0)) { chunk_size = -7; } end_of_subchunk = offset + 8 + chunk_size; if(b_sensor_read && b_gps_read) { break; } //qInfo() << chunk_id << ":" << end_of_subchunk << " =" << chunk_size; RMfseek(_file,end_of_subchunk,SEEK_SET); } _isValid = true; return 0; } #endif while (RMftell(_file)bMOVSize = true; _preInfo->movSize = chunk_size; } #endif // 처리할 필요 없음 #if (SENSOR_AVI_SUBTITLE) if(_readMode == VideoReadSensor) { parse_movi_list(chunk_size); } #endif } else if (strcasecmp("idx1",chunk_id)==0) // 인덱스 처리 { RMfseek(_file,RMftell(_file)-4,SEEK_SET); #if (DEBUG_AVI_FORMAT) parse_idx1(chunk_size); #endif } else { #if (DEBUG_AVI_FORMAT) printf(" Unknown chunk at %d (%4s)\n",(int)RMftell(_file)-8,chunk_type); #endif if (chunk_size==0) { break; } } // 필요한 정보 모두 수집되었는지 확인 if(_readMode == VideoReadDuration && _preInfo != NULL && _preInfo->bDuration == true) { _isValid = true; return 0; } #if (CHECK_VIDEO_BITRATE) else if(_readMode == VideoReadMOVSize && _preInfo != NULL && _preInfo->bDuration == true && _preInfo->bMOVSize) { _isValid = true; return 0; } #endif RMfseek(_file,end_of_subchunk,SEEK_SET); #if (DEBUG_AVI_FORMAT) printf(" }\n"); #endif } #if (DEBUG_AVI_FORMAT) printf("}\n"); #endif _isValid = true; return 0; } bool AVIRiff::duration(RMfile in, VideoPreInfo* info) { AVIRiff avi = AVIRiff(in,VideoReadDuration,info); return avi.isValid(); } #if (CHECK_VIDEO_BITRATE) bool AVIRiff::movSize(RMfile in, VideoPreInfo* info) { AVIRiff avi = AVIRiff(in,VideoReadMOVSize,info); return avi.isValid(); } #endif #endif // #if (FILE_FORMAT_AVI)