Type Parser::parse_y_symbol(char& c, std::string& str) { Type token = lexer->get_token(c, str); if(token == HASH) { token = lexer->get_token(c, str); if(token == MINUS) { token = lexer->get_token(c, str); } if(token != DEC && token != HEX) print_fatal("Syntax error: expected hex or dec but got %s\n", str.c_str()); } else if(token == REGISTER) { token = lexer->get_token(c, str); if(token == RIGHT_SQ_BRACKET) return token; if(token == COMMA) { check_next_token(INSTRUCTION, c, str); check_next_token(WHITESPACE, c, str); check_next_token(HASH, c, str); check_next_token(DEC, c, str); } else print_fatal("Syntax error: expected ']' or ',' but got %s\n", str.c_str()); } else print_fatal("Syntax error: expected hash or register but got %s\n", str.c_str()); return lexer->get_token(c, str); }
UrRealtimeCommunication::UrRealtimeCommunication( std::condition_variable& msg_cond, std::string host, unsigned int safety_count_max) { robot_state_ = new RobotStateRT(msg_cond); bzero((char *) &serv_addr_, sizeof(serv_addr_)); sockfd_ = socket(AF_INET, SOCK_STREAM, 0); if (sockfd_ < 0) { print_fatal("ERROR opening socket"); } server_ = gethostbyname(host.c_str()); if (server_ == NULL) { print_fatal("ERROR, no such host"); } serv_addr_.sin_family = AF_INET; bcopy((char *) server_->h_addr, (char *)&serv_addr_.sin_addr.s_addr, server_->h_length); serv_addr_.sin_port = htons(30003); flag_ = 1; setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); setsockopt(sockfd_, IPPROTO_TCP, TCP_QUICKACK, (char *) &flag_, sizeof(int)); setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (char *) &flag_, sizeof(int)); fcntl(sockfd_, F_SETFL, O_NONBLOCK); connected_ = false; keepalive_ = false; safety_count_ = safety_count_max + 1; safety_count_max_ = safety_count_max; }
UrRealtimeCommunication::UrRealtimeCommunication( std::condition_variable& msg_cond, const std::string& host, const unsigned int port /*=30003*/, unsigned int safety_count_max/*=12*/) { robot_state_ = new RobotStateRT(msg_cond); memset((char *) &serv_addr_, 0, sizeof(serv_addr_)); sockfd_ = socket(AF_INET, SOCK_STREAM, 0); if (sockfd_ < 0) { print_fatal("ERROR opening socket"); } server_ = gethostbyname(host.c_str()); if (server_ == NULL) { print_fatal("ERROR, no such host"); } serv_addr_.sin_family = AF_INET; memcpy((char *)&serv_addr_.sin_addr.s_addr, (char *)server_->h_addr, server_->h_length); serv_addr_.sin_port = htons(port); flag_ = 1; setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (char *) &flag_, sizeof(int)); SetNonBlocking(sockfd_, true); connected_ = false; keepalive_ = false; safety_count_ = safety_count_max + 1; safety_count_max_ = safety_count_max; }
void Lexer::initialize_set(char* filename, std::set <uint64_t>* s) { FILE* file = fopen(filename, "r+"); if(!file) { print_fatal("Couldn't open set file!\n"); } print_log("Set file opened\n"); char* line = NULL; size_t line_len = 0; while(getline(&line, &line_len, file) != -1) { line_len = strlen(line); if(line[line_len-1] == '\n') line[--line_len] = '\0'; unsigned it = 0; uint64_t hash = 0; while(it < line_len) { hash <<= 8; hash += line[it++]; } if(s->find(hash) != s->end()) { print_fatal("TWO STRINGS WITH SAME HASH!\n"); } s->insert(hash); line = NULL; line_len = 0; } print_log("Filled set\n"); fclose(file); }
bool UrRealtimeCommunication::start() { fd_set writefds; struct timeval timeout; keepalive_ = true; print_debug("Realtime port: Connecting..."); connect(sockfd_, (struct sockaddr *) &serv_addr_, sizeof(serv_addr_)); FD_ZERO(&writefds); FD_SET(sockfd_, &writefds); timeout.tv_sec = 10; timeout.tv_usec = 0; select(sockfd_ + 1, NULL, &writefds, NULL, &timeout); int flag_len; getsockopt(sockfd_, SOL_SOCKET, SO_ERROR, (char*) &flag_, &flag_len); if (flag_ < 0) { print_fatal("Error connecting to RT port 30003"); return false; } sockaddr_in name; socklen_t namelen = sizeof(name); int err = getsockname(sockfd_, (sockaddr*) &name, &namelen); if (err < 0) { print_fatal("Could not get local IP"); CloseSocket(sockfd_); return false; } char str[18]; inet_ntop(AF_INET, &name.sin_addr, str, 18); local_ip_ = str; comThread_ = std::thread(&UrRealtimeCommunication::run, this); return true; }
Instruction* Parser::parse_start_symbol(Type token, char& c, std::string& str) { Instruction* instruction = new Instruction(); if(token == HEX || token == DEC) { check_next_token(WHITESPACE, c, str); check_next_token(LESS_THAN, c, str); check_next_token(STRING, c, str); check_next_token(AT, c, str); token = lexer->get_token(c, str); if(token == AT) { token = lexer->get_token(c, str); } parse_x_symbol(token, c, str); check_next_token(COLON, c, str); check_next_token(NEWLINE, c, str); return NULL; } else if(token == WHITESPACE) { check_next_token(HEX, c, str); sscanf(str.c_str(), " %x", &instruction->address); check_next_token(COLON, c, str); check_next_token(WHITESPACE, c, str); check_next_token(HEX, c, str); sscanf(str.c_str(), " %x", &instruction->opcode); check_next_token(WHITESPACE, c, str); token = parse_instruction_symbol(c, str, *instruction); if(token == WHITESPACE) { parse_comment_symbol(c, str); check_next_token(NEWLINE, c, str); } else if(token != NEWLINE) { print_fatal("Syntax error: expected newline after instruction, got: %s\n", str.c_str()); } print_log("Got instruction, addr: %x \t opcode: %x \t %s\n", instruction->address, instruction->opcode, instruction->name.c_str()); return instruction; } else if(token != NEWLINE) { print_fatal("Syntax error: expected starting symbol, got: %s\n", str.c_str()); return NULL; } return NULL; //print_log("Syntax accepted, back to starting symbol\n"); }
void Parser::parse_x_symbol(Type token, char& c, std::string& str) { if(token != STRING) print_fatal("Syntax error: expected string but got %s\n", str.c_str()); token = lexer->get_token(c, str); if(token == MINUS || token == PLUS) { check_next_token(HEX, c, str); check_next_token(MORE_THAN, c, str); } else if(token != MORE_THAN) { print_fatal("Syntax error: expected '>' but got %s which is %s\n", str.c_str(), type_to_string(token)); } }
void free_object (object *obj) { if (NULL == obj) { return; } else if (SCM_VOID == obj->type) free (obj); else if (SCM_ERROR == obj->type) { free (((error_object *) obj)->msg); free (obj); } else if (SCM_ATOM == obj->type) { free (((atom_object *) obj)->name); free (obj); } else if (SCM_BOOL == obj->type) { free (obj); } else if (SCM_VARIABLE == obj->type) { free (((variable_object *) obj)->name); free_object (((variable_object *) obj)->value); free (obj); } else if (SCM_NUMBER == obj->type) { free (obj); } else if (SCM_STRING == obj->type) { free (((string_object *) obj)->str); free (obj); } else if (SCM_PAIR == obj->type) { free_object (car (obj)); free_object (cdr (obj)); free (obj); } else if (SCM_FUNC == obj->type) { free (obj); } else if (SCM_LAMBDA == obj->type) { free_object (((lambda_object *) obj)->args); free_object (((lambda_object *) obj)->sexp); free (obj); } else { print_fatal (ETYPE); exit (1); } }
bool UrCommunication::start() { keepalive_ = true; uint8_t buf[512]; unsigned int bytes_read; std::string cmd; bzero(buf, 512); print_debug("Acquire firmware version: Connecting..."); if (connect(pri_sockfd_, (struct sockaddr *) &pri_serv_addr_, sizeof(pri_serv_addr_)) < 0) { print_fatal("Error connecting to get firmware version"); return false; } print_debug("Acquire firmware version: Got connection"); bytes_read = read(pri_sockfd_, buf, 512); setsockopt(pri_sockfd_, IPPROTO_TCP, TCP_QUICKACK, (char *) &flag_, sizeof(int)); robot_state_->unpack(buf, bytes_read); //wait for some traffic so the UR socket doesn't die in version 3.1. std::this_thread::sleep_for(std::chrono::milliseconds(500)); char tmp[64]; sprintf(tmp, "Firmware version detected: %.7f", robot_state_->getVersion()); print_debug(tmp); close(pri_sockfd_); print_debug( "Switching to secondary interface for masterboard data: Connecting..."); fd_set writefds; struct timeval timeout; connect(sec_sockfd_, (struct sockaddr *) &sec_serv_addr_, sizeof(sec_serv_addr_)); FD_ZERO(&writefds); FD_SET(sec_sockfd_, &writefds); timeout.tv_sec = 10; timeout.tv_usec = 0; select(sec_sockfd_ + 1, NULL, &writefds, NULL, &timeout); unsigned int flag_len; getsockopt(sec_sockfd_, SOL_SOCKET, SO_ERROR, &flag_, &flag_len); if (flag_ < 0) { print_fatal("Error connecting to secondary interface"); return false; } print_debug("Secondary interface: Got connection"); comThread_ = std::thread(&UrCommunication::run, this); return true; }
void Parser::open_file(char* filepath) { input_file = fopen(filepath, "r"); if(input_file == NULL) { print_fatal("Error while reading file: %s\n", filepath); } print_log("File \"%s\" opened\n", filepath); }
void Parser::check_next_token(Type token, char& c, std::string& str) { Type read_token = lexer->get_token(c, str); if(read_token == HEX_OR_INSTRUCTION && (token == HEX || token == INSTRUCTION)) return; if(read_token == DEC && token == HEX) return; if(read_token != token) { print_fatal("Syntax error: expected %s but got %s which is %s\n", type_to_string(token), str.c_str(), type_to_string(read_token)); } }
UrCommunication::UrCommunication(std::condition_variable& msg_cond, std::string host) { robot_state_ = new RobotState(msg_cond); bzero((char *) &pri_serv_addr_, sizeof(pri_serv_addr_)); bzero((char *) &sec_serv_addr_, sizeof(sec_serv_addr_)); pri_sockfd_ = socket(AF_INET, SOCK_STREAM, 0); if (pri_sockfd_ < 0) { print_fatal("ERROR opening socket pri_sockfd"); } sec_sockfd_ = socket(AF_INET, SOCK_STREAM, 0); if (sec_sockfd_ < 0) { print_fatal("ERROR opening socket sec_sockfd"); } server_ = gethostbyname(host.c_str()); if (server_ == NULL) { print_fatal("ERROR, unknown host"); } pri_serv_addr_.sin_family = AF_INET; sec_serv_addr_.sin_family = AF_INET; bcopy((char *) server_->h_addr, (char *)&pri_serv_addr_.sin_addr.s_addr, server_->h_length); bcopy((char *) server_->h_addr, (char *)&sec_serv_addr_.sin_addr.s_addr, server_->h_length); pri_serv_addr_.sin_port = htons(30001); sec_serv_addr_.sin_port = htons(30002); flag_ = 1; setsockopt(pri_sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); setsockopt(pri_sockfd_, IPPROTO_TCP, TCP_QUICKACK, (char *) &flag_, sizeof(int)); setsockopt(pri_sockfd_, SOL_SOCKET, SO_REUSEADDR, (char *) &flag_, sizeof(int)); setsockopt(sec_sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); setsockopt(sec_sockfd_, IPPROTO_TCP, TCP_QUICKACK, (char *) &flag_, sizeof(int)); setsockopt(sec_sockfd_, SOL_SOCKET, SO_REUSEADDR, (char *) &flag_, sizeof(int)); fcntl(sec_sockfd_, F_SETFL, O_NONBLOCK); connected_ = false; keepalive_ = false; }
void Parser::parse_comment_symbol(char& c, std::string& str) { Type token = lexer->get_token(c, str); if(token == DOUBLE_SLASH) { check_next_token(WHITESPACE, c, str); check_next_token(HASH, c, str); token = lexer->get_token(c, str); if(token == MINUS) check_next_token(DEC, c, str); else if(token != DEC) print_fatal("Syntax error: expected DEC in comment but got %s\n", str.c_str()); } else if(token == SEMICOLON) { check_next_token(WHITESPACE, c, str); check_next_token(STRING, c, str); } else { print_fatal("Syntax error: expected comment but got %s\n", str.c_str()); } }
void print (object *obj) { if (NULL == obj) { printf ("()"); return; } if (SCM_VOID == obj->type); else if (SCM_ERROR == obj->type) printf ("ERROR: %s", ((error_object *) obj)->msg); else if (SCM_ATOM == obj->type) printf ("%s", ((atom_object *) obj)->name); else if (SCM_BOOL == obj->type) printf ("%s", ((bool_object *) obj)->value ? "#t" : "#f"); else if (SCM_VARIABLE == obj->type) print (((variable_object *) obj)->value); else if (SCM_NUMBER == obj->type) printf ("%lf", ((number_object *) obj)->num); else if (SCM_STRING == obj->type) printf ("\"%s\"", ((string_object *) obj)->str); else if (SCM_PAIR == obj->type) { printf ("("); print (car (obj)); printf (" . "); print (cdr (obj)); printf (")"); } else if (SCM_FUNC == obj->type) { printf ("#<procedure builtin>"); } else if (SCM_LAMBDA == obj->type) { printf ("#<procedure lambda "); print (((lambda_object *) obj)->args); printf (">"); } else { print_fatal (ETYPE); exit (1); } }
object * copy_object (object *obj) { object *ret = NULL; if (NULL == obj) return NULL; else if (SCM_VOID == obj->type) ret = SCM_void (); else if (SCM_ERROR == obj->type) ret = SCM_error (((error_object *) obj)->error, ((error_object *) obj)->msg); else if (SCM_ATOM == obj->type) ret = SCM_atom (((atom_object *) obj)->name); else if (SCM_BOOL == obj->type) ret = SCM_bool (((bool_object *) obj)->value); else if (SCM_VARIABLE == obj->type) ret = SCM_variable (((variable_object *) obj)->name, copy_object (((variable_object *) obj)->value)); else if (SCM_NUMBER == obj->type) ret = SCM_number_from_double (((number_object *) obj)->num); else if (SCM_STRING == obj->type) ret = SCM_string (((string_object *) obj)->str); else if (SCM_PAIR == obj->type) ret = SCM_cons (copy_object (car (obj)), copy_object (cdr (obj))); else if (SCM_FUNC == obj->type) ret = SCM_func (((func_object *) obj)->fn); else if (SCM_LAMBDA == obj->type) ret = SCM_lambda (copy_object (((lambda_object *) obj)->args), copy_object (((lambda_object *) obj)->sexp)); else { print_fatal (ETYPE); exit (1); } return ret; }
void UrRealtimeCommunication::run() { uint8_t buf[2048]; int bytes_read; memset(buf, 0, 2048); struct timeval timeout; fd_set readfds; FD_ZERO(&readfds); FD_SET(sockfd_, &readfds); print_debug("Realtime port: Got connection"); connected_ = true; while (keepalive_) { while (connected_ && keepalive_) { timeout.tv_sec = 0; //do this each loop as selects modifies timeout timeout.tv_usec = 500000; // timeout of 0.5 sec select(sockfd_ + 1, &readfds, NULL, NULL, &timeout); bytes_read = recv(sockfd_, (char*) buf, 2048, 0); if (bytes_read > 0) { setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); robot_state_->unpack(buf); if (safety_count_ == safety_count_max_) { setSpeed(0., 0., 0., 0., 0., 0.); } safety_count_ += 1; } else { connected_ = false; CloseSocket(sockfd_); } } if (keepalive_) { //reconnect ofLog()<<"Realtime port: No connection. Is controller crashed? Will try to reconnect in 10 seconds..."<<endl; sockfd_ = socket(AF_INET, SOCK_STREAM, 0); if (sockfd_ < 0) { print_fatal("ERROR opening socket"); } flag_ = 1; setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (char *) &flag_, sizeof(int)); SetNonBlocking(sockfd_, true); while (keepalive_ && !connected_) { std::this_thread::sleep_for(std::chrono::seconds(10)); fd_set writefds; connect(sockfd_, (struct sockaddr *) &serv_addr_, sizeof(serv_addr_)); FD_ZERO(&writefds); FD_SET(sockfd_, &writefds); select(sockfd_ + 1, NULL, &writefds, NULL, NULL); int flag_len; getsockopt(sockfd_, SOL_SOCKET, SO_ERROR, (char*)&flag_, &flag_len); if (flag_ < 0) { print_error("Error re-connecting to RT port 30003. Is controller started? Will try to reconnect in 10 seconds..."); } else { connected_ = true; print_info("Realtime port: Reconnected"); } } } } setSpeed(0., 0., 0., 0., 0., 0.); CloseSocket(sockfd_); }
Type Parser::parse_operands_symbol(char& c, std::string& str) { Type token = lexer->get_token(c, str); for(int i = 0; i < 4; ++i) { if(token == REGISTER) { token = lexer->get_token(c, str); } else if(token == HASH) { token = lexer->get_token(c, str); if(token == MINUS) token = lexer->get_token(c, str); if(token != DEC && token != HEX) print_fatal("Syntax error: expected hex or dec but got %s\n", str.c_str()); token = lexer->get_token(c, str); } else if(token == LEFT_SQ_BRACKET) { check_next_token(REGISTER, c, str); token = lexer->get_token(c, str); if(token == COMMA) { token = parse_y_symbol(c, str); } if(token != RIGHT_SQ_BRACKET) print_fatal("Syntax error: expected ',' or ']' but got %s\n", str.c_str()); token = lexer->get_token(c, str); if(token == EXCLAMATION) token = lexer->get_token(c, str); } else if(token == HEX || token == DEC) { parse_z_symbol(c, str); token = lexer->get_token(c, str); } else if(token == STRING || token == CONDITION) { token = lexer->get_token(c, str); } else if(token == INSTRUCTION) { token = lexer->get_token(c, str); if(token == NEWLINE) return token; if(token != WHITESPACE) print_fatal("Syntax error: expected WHITESPACE but got %s\n", str.c_str()); check_next_token(HASH, c, str); check_next_token(DEC, c, str); token = lexer->get_token(c, str); } else break; if(token == COMMA) { token = lexer->get_token(c, str); if(token == WHITESPACE) token = lexer->get_token(c, str); } } return token; }
void UrCommunication::run() { uint8_t buf[2048]; int bytes_read; bzero(buf, 2048); struct timeval timeout; fd_set readfds; FD_ZERO(&readfds); FD_SET(sec_sockfd_, &readfds); connected_ = true; while (keepalive_) { while (connected_ && keepalive_) { timeout.tv_sec = 0; //do this each loop as selects modifies timeout timeout.tv_usec = 500000; // timeout of 0.5 sec select(sec_sockfd_ + 1, &readfds, NULL, NULL, &timeout); bytes_read = read(sec_sockfd_, buf, 2048); // usually only up to 1295 bytes if (bytes_read > 0) { setsockopt(sec_sockfd_, IPPROTO_TCP, TCP_QUICKACK, (char *) &flag_, sizeof(int)); robot_state_->unpack(buf, bytes_read); } else { connected_ = false; robot_state_->setDisconnected(); close(sec_sockfd_); } } if (keepalive_) { //reconnect print_warning("Secondary port: No connection. Is controller crashed? Will try to reconnect in 10 seconds..."); sec_sockfd_ = socket(AF_INET, SOCK_STREAM, 0); if (sec_sockfd_ < 0) { print_fatal("ERROR opening secondary socket"); } flag_ = 1; setsockopt(sec_sockfd_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag_, sizeof(int)); setsockopt(sec_sockfd_, IPPROTO_TCP, TCP_QUICKACK, (char *) &flag_, sizeof(int)); setsockopt(sec_sockfd_, SOL_SOCKET, SO_REUSEADDR, (char *) &flag_, sizeof(int)); fcntl(sec_sockfd_, F_SETFL, O_NONBLOCK); while (keepalive_ && !connected_) { std::this_thread::sleep_for(std::chrono::seconds(10)); fd_set writefds; connect(sec_sockfd_, (struct sockaddr *) &sec_serv_addr_, sizeof(sec_serv_addr_)); FD_ZERO(&writefds); FD_SET(sec_sockfd_, &writefds); select(sec_sockfd_ + 1, NULL, &writefds, NULL, NULL); unsigned int flag_len; getsockopt(sec_sockfd_, SOL_SOCKET, SO_ERROR, &flag_, &flag_len); if (flag_ < 0) { print_error("Error re-connecting to port 30002. Is controller started? Will try to reconnect in 10 seconds..."); } else { connected_ = true; print_info("Secondary port: Reconnected"); } } } } //wait for some traffic so the UR socket doesn't die in version 3.1. std::this_thread::sleep_for(std::chrono::milliseconds(500)); close(sec_sockfd_); }
/* check FLV file validity */ int check_flv_file(const flvmeta_opts * opts) { flv_stream * flv_in; flv_header header; int errors, warnings; int result; char message[256]; uint32 prev_tag_size, tag_number; uint32 last_timestamp, last_video_timestamp, last_audio_timestamp; struct stat file_stats; int have_audio, have_video; flvmeta_opts opts_loc; flv_info info; int have_desync; int have_on_metadata; file_offset_t on_metadata_offset; amf_data * on_metadata; int have_on_last_second; uint32 on_last_second_timestamp; int have_prev_audio_tag; flv_audio_tag prev_audio_tag; int have_prev_video_tag; flv_video_tag prev_video_tag; int video_frames_number, keyframes_number; prev_audio_tag = 0; prev_video_tag = 0; have_audio = have_video = 0; tag_number = 0; last_timestamp = last_video_timestamp = last_audio_timestamp = 0; have_desync = 0; have_prev_audio_tag = have_prev_video_tag = 0; video_frames_number = keyframes_number = 0; have_on_metadata = 0; on_metadata_offset = 0; on_metadata = NULL; have_on_last_second = 0; on_last_second_timestamp = 0; /* file stats */ if (stat(opts->input_file, &file_stats) != 0) { return ERROR_OPEN_READ; } /* open file for reading */ flv_in = flv_open(opts->input_file); if (flv_in == NULL) { return ERROR_OPEN_READ; } errors = warnings = 0; report_start(opts); /** check header **/ /* check signature */ result = flv_read_header(flv_in, &header); if (result == FLV_ERROR_EOF) { print_fatal("F11001", 0, "unexpected end of file in header"); goto end; } else if (result == FLV_ERROR_NO_FLV) { print_fatal("F11002", 0, "FLV signature not found in header"); goto end; } /* version */ if (header.version != FLV_VERSION) { sprintf(message, "header version should be 1, %d found instead", header.version); print_error("E11003", 3, message); } /* video and audio flags */ if (!flv_header_has_audio(header) && !flv_header_has_video(header)) { print_error("E11004", 4, "header signals the file does not contain video tags or audio tags"); } else if (!flv_header_has_audio(header)) { print_info("I11005", 4, "header signals the file does not contain audio tags"); } else if (!flv_header_has_video(header)) { print_warning("W11006", 4, "header signals the file does not contain video tags"); } /* reserved flags */ if (header.flags & 0xFA) { print_error("E11007", 4, "header reserved flags are not zero"); } /* offset */ if (flv_header_get_offset(header) != 9) { sprintf(message, "header offset should be 9, %d found instead", flv_header_get_offset(header)); print_error("E11008", 5, message); } /** check first previous tag size **/ result = flv_read_prev_tag_size(flv_in, &prev_tag_size); if (result == FLV_ERROR_EOF) { print_fatal("F12009", 9, "unexpected end of file in previous tag size"); goto end; } else if (prev_tag_size != 0) { sprintf(message, "first previous tag size should be 0, %d found instead", prev_tag_size); print_error("E12010", 9, message); } /* we reached the end of file: no tags in file */ if (flv_get_offset(flv_in) == file_stats.st_size) { print_fatal("F10011", 13, "file does not contain tags"); goto end; } /** read tags **/ while (flv_get_offset(flv_in) < file_stats.st_size) { flv_tag tag; file_offset_t offset; uint32 body_length, timestamp, stream_id; int decr_timestamp_signaled; result = flv_read_tag(flv_in, &tag); if (result != FLV_OK) { print_fatal("F20012", flv_get_offset(flv_in), "unexpected end of file in tag"); goto end; } ++tag_number; offset = flv_get_current_tag_offset(flv_in); body_length = flv_tag_get_body_length(tag); timestamp = flv_tag_get_timestamp(tag); stream_id = flv_tag_get_stream_id(tag); /* check tag type */ if (tag.type != FLV_TAG_TYPE_AUDIO && tag.type != FLV_TAG_TYPE_VIDEO && tag.type != FLV_TAG_TYPE_META ) { sprintf(message, "unknown tag type %hhd", tag.type); print_error("E30013", offset, message); } /* check consistency with global header */ if (!have_video && tag.type == FLV_TAG_TYPE_VIDEO) { if (!flv_header_has_video(header)) { print_warning("W11014", offset, "video tag found despite header signaling the file contains no video"); } have_video = 1; } if (!have_audio && tag.type == FLV_TAG_TYPE_AUDIO) { if (!flv_header_has_audio(header)) { print_warning("W11015", offset, "audio tag found despite header signaling the file contains no audio"); } have_audio = 1; } /* check body length */ if (body_length > (file_stats.st_size - flv_get_offset(flv_in))) { sprintf(message, "tag body length (%d bytes) exceeds file size", body_length); print_fatal("F20016", offset + 1, message); goto end; } else if (body_length > MAX_ACCEPTABLE_TAG_BODY_LENGTH) { sprintf(message, "tag body length (%d bytes) is abnormally large", body_length); print_warning("W20017", offset + 1, message); } else if (body_length == 0) { print_warning("W20018", offset + 1, "tag body length is zero"); } /** check timestamp **/ decr_timestamp_signaled = 0; /* check whether first timestamp is zero */ if (tag_number == 1 && timestamp != 0) { sprintf(message, "first timestamp should be zero, %d found instead", timestamp); print_error("E40019", offset + 4, message); } /* check whether timestamps decrease in a given stream */ if (tag.type == FLV_TAG_TYPE_AUDIO) { if (last_audio_timestamp > timestamp) { sprintf(message, "audio tag timestamps are decreasing from %d to %d", last_audio_timestamp, timestamp); print_error("E40020", offset + 4, message); } last_audio_timestamp = timestamp; decr_timestamp_signaled = 1; } if (tag.type == FLV_TAG_TYPE_VIDEO) { if (last_video_timestamp > timestamp) { sprintf(message, "video tag timestamps are decreasing from %d to %d", last_video_timestamp, timestamp); print_error("E40021", offset + 4, message); } last_video_timestamp = timestamp; decr_timestamp_signaled = 1; } /* check for overflow error */ if (last_timestamp > timestamp && last_timestamp - timestamp > 0xF00000) { print_error("E40022", offset + 4, "extended bits not used after timestamp overflow"); } /* check whether timestamps decrease globally */ else if (!decr_timestamp_signaled && last_timestamp > timestamp && last_timestamp - timestamp >= 1000) { sprintf(message, "timestamps are decreasing from %d to %d", last_timestamp, timestamp); print_error("E40023", offset + 4, message); } last_timestamp = timestamp; /* check for desyncs between audio and video: one second or more is suspicious */ if (have_video && have_audio && !have_desync && labs(last_video_timestamp - last_audio_timestamp) >= 1000) { sprintf(message, "audio and video streams are desynchronized by %ld ms", labs(last_video_timestamp - last_audio_timestamp)); print_warning("W40024", offset + 4, message); have_desync = 1; /* do not repeat */ } /** stream id must be zero **/ if (stream_id != 0) { sprintf(message, "tag stream id must be zero, %d found instead", stream_id); print_error("E20025", offset + 8, message); } /* check tag body contents only if not empty */ if (body_length > 0) { /** check audio info **/ if (tag.type == FLV_TAG_TYPE_AUDIO) { flv_audio_tag at; uint8_bitmask audio_format; result = flv_read_audio_tag(flv_in, &at); if (result == FLV_ERROR_EOF) { print_fatal("F20012", offset + 11, "unexpected end of file in tag"); goto end; } /* check whether the format varies between tags */ if (have_prev_audio_tag && prev_audio_tag != at) { print_warning("W51026", offset + 11, "audio format changed since last tag"); } /* check format */ audio_format = flv_audio_tag_sound_format(at); if (audio_format == 12 || audio_format == 13) { sprintf(message, "unknown audio format %d", audio_format); print_warning("W51027", offset + 11, message); } else if (audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_G711_A || audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_G711_MU || audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_RESERVED || audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_MP3_8 || audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_DEVICE_SPECIFIC ) { sprintf(message, "audio format %d is reserved for internal use", audio_format); print_warning("W51028", offset + 11, message); } /* check consistency, see flash video spec */ if (flv_audio_tag_sound_rate(at) != FLV_AUDIO_TAG_SOUND_RATE_44 && audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_AAC ) { print_warning("W51029", offset + 11, "audio data in AAC format should have a 44KHz rate, field will be ignored"); } if (flv_audio_tag_sound_type(at) == FLV_AUDIO_TAG_SOUND_TYPE_STEREO && (audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_NELLYMOSER || audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_NELLYMOSER_16_MONO || audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_NELLYMOSER_8_MONO) ) { print_warning("W51030", offset + 11, "audio data in Nellymoser format cannot be stereo, field will be ignored"); } else if (flv_audio_tag_sound_type(at) == FLV_AUDIO_TAG_SOUND_TYPE_MONO && audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_AAC ) { print_warning("W51031", offset + 11, "audio data in AAC format should be stereo, field will be ignored"); } else if (audio_format == FLV_AUDIO_TAG_SOUND_FORMAT_LINEAR_PCM) { print_warning("W51032", offset + 11, "audio data in Linear PCM, platform endian format should not be used because of non-portability"); } prev_audio_tag = at; have_prev_audio_tag = 1; } /** check video info **/ else if (tag.type == FLV_TAG_TYPE_VIDEO) { flv_video_tag vt; uint8_bitmask video_frame_type, video_codec; video_frames_number++; result = flv_read_video_tag(flv_in, &vt); if (result == FLV_ERROR_EOF) { print_fatal("F20012", offset + 11, "unexpected end of file in tag"); goto end; } /* check whether the format varies between tags */ if (have_prev_video_tag && flv_video_tag_codec_id(prev_video_tag) != flv_video_tag_codec_id(vt)) { print_warning("W60033", offset + 11, "video format changed since last tag"); } /* check video frame type */ video_frame_type = flv_video_tag_frame_type(vt); if (video_frame_type != FLV_VIDEO_TAG_FRAME_TYPE_KEYFRAME && video_frame_type != FLV_VIDEO_TAG_FRAME_TYPE_INTERFRAME && video_frame_type != FLV_VIDEO_TAG_FRAME_TYPE_DISPOSABLE_INTERFRAME && video_frame_type != FLV_VIDEO_TAG_FRAME_TYPE_GENERATED_KEYFRAME && video_frame_type != FLV_VIDEO_TAG_FRAME_TYPE_COMMAND_FRAME ) { sprintf(message, "unknown video frame type %d", video_frame_type); print_error("E60034", offset + 11, message); } if (video_frame_type == FLV_VIDEO_TAG_FRAME_TYPE_KEYFRAME) { keyframes_number++; } /* check whether first frame is a keyframe */ if (!have_prev_video_tag && video_frame_type != FLV_VIDEO_TAG_FRAME_TYPE_KEYFRAME) { print_warning("W60035", offset + 11, "first video frame is not a keyframe, playback will suffer"); } /* check video codec */ video_codec = flv_video_tag_codec_id(vt); if (video_codec != FLV_VIDEO_TAG_CODEC_JPEG && video_codec != FLV_VIDEO_TAG_CODEC_SORENSEN_H263 && video_codec != FLV_VIDEO_TAG_CODEC_SCREEN_VIDEO && video_codec != FLV_VIDEO_TAG_CODEC_ON2_VP6 && video_codec != FLV_VIDEO_TAG_CODEC_ON2_VP6_ALPHA && video_codec != FLV_VIDEO_TAG_CODEC_SCREEN_VIDEO_V2 && video_codec != FLV_VIDEO_TAG_CODEC_AVC ) { sprintf(message, "unknown video codec id %d", video_codec); print_error("E61034", offset + 11, message); } /* according to spec, JPEG codec is not currently used */ if (video_codec == FLV_VIDEO_TAG_CODEC_JPEG) { print_warning("W61035", offset + 11, "JPEG codec not currently used"); } prev_video_tag = vt; have_prev_video_tag = 1; } /** check script data info **/ else if (tag.type == FLV_TAG_TYPE_META) { amf_data * name; amf_data * data; result = flv_read_metadata(flv_in, &name, &data); if (result == FLV_ERROR_EOF) { print_fatal("F20012", offset + 11, "unexpected end of file in tag"); amf_data_free(name); amf_data_free(data); goto end; } else if (result == FLV_ERROR_EMPTY_TAG) { print_warning("W70038", offset + 11, "empty metadata tag"); } else if (result == FLV_ERROR_INVALID_METADATA_NAME) { print_error("E70039", offset + 11, "invalid metadata name"); } else if (result == FLV_ERROR_INVALID_METADATA) { print_error("E70039", offset + 11, "invalid metadata"); } else if (amf_data_get_type(name) != AMF_TYPE_STRING) { /* name type checking */ sprintf(message, "invalid metadata name type: %d, should be a string (2)", amf_data_get_type(name)); print_error("E70038", offset, message); } else { /* empty name checking */ if (amf_string_get_size(name) == 0) { print_warning("W70038", offset, "empty metadata name"); } /* check whether all body size has been read */ if (flv_in->current_tag_body_length > 0) { sprintf(message, "%d bytes not read in tag body after metadata end", body_length - flv_in->current_tag_body_length); print_warning("W70040", flv_get_offset(flv_in), message); } else if (flv_in->current_tag_body_length < 0) { sprintf(message, "%d bytes missing from tag body after metadata end", flv_in->current_tag_body_length - body_length); print_warning("W70041", flv_get_offset(flv_in), message); } /* onLastSecond checking */ if (!strcmp((char*)amf_string_get_bytes(name), "onLastSecond")) { if (have_on_last_second == 0) { have_on_last_second = 1; on_last_second_timestamp = timestamp; } else { print_warning("W70038", offset, "duplicate onLastSecond event"); } } /* onMetaData checking */ if (!strcmp((char*)amf_string_get_bytes(name), "onMetaData")) { if (have_on_metadata == 0) { have_on_metadata = 1; on_metadata_offset = offset; on_metadata = amf_data_clone(data); /* check onMetadata type */ if (amf_data_get_type(on_metadata) != AMF_TYPE_ASSOCIATIVE_ARRAY) { sprintf(message, "invalid onMetaData data type: %d, should be an associative array (8)", amf_data_get_type(on_metadata)); print_error("E70038", offset, message); } /* onMetaData must be the first tag at 0 timestamp */ if (tag_number != 1) { print_warning("W70038", offset, "onMetadata event found after the first tag"); } if (timestamp != 0) { print_warning("W70038", offset, "onMetadata event found after timestamp zero"); } } else { print_warning("W70038", offset, "duplicate onMetaData event"); } } /* unknown metadata name */ if (strcmp((char*)amf_string_get_bytes(name), "onMetaData") && strcmp((char*)amf_string_get_bytes(name), "onCuePoint") && strcmp((char*)amf_string_get_bytes(name), "onLastSecond")) { sprintf(message, "unknown metadata event name: '%s'", (char*)amf_string_get_bytes(name)); print_info("I70039", flv_get_offset(flv_in), message); } } amf_data_free(name); amf_data_free(data); } } /* check body length against previous tag size */ result = flv_read_prev_tag_size(flv_in, &prev_tag_size); if (result != FLV_OK) { print_fatal("F12036", flv_get_offset(flv_in), "unexpected end of file after tag"); goto end; } if (prev_tag_size != FLV_TAG_SIZE + body_length) { sprintf(message, "previous tag size should be %d, %d found instead", FLV_TAG_SIZE + body_length, prev_tag_size); print_error("E12037", flv_get_offset(flv_in), message); goto end; } } /** final checks */ /* check consistency with global header */ if (!have_video && flv_header_has_video(header)) { print_warning("W11038", 4, "no video tag found despite header signaling the file contains video"); } if (!have_audio && flv_header_has_audio(header)) { print_warning("W11039", 4, "no audio tag found despite header signaling the file contains audio"); } /* check last timestamps */ if (have_video && have_audio && labs(last_audio_timestamp - last_video_timestamp) >= 1000) { if (last_audio_timestamp > last_video_timestamp) { sprintf(message, "video stops %d ms before audio", last_audio_timestamp - last_video_timestamp); print_warning("W40040", file_stats.st_size, message); } else { sprintf(message, "audio stops %d ms before video", last_video_timestamp - last_audio_timestamp); print_warning("W40041", file_stats.st_size, message); } } /* check video keyframes */ if (have_video && keyframes_number == 0) { print_warning("W60042", file_stats.st_size, "no keyframe detected, file is probably broken or incomplete"); } if (have_video && keyframes_number == video_frames_number) { print_warning("W60043", file_stats.st_size, "only keyframes detected, probably inefficient compression scheme used"); } /* only keyframes + onLastSecond bug */ if (have_video && have_on_last_second && keyframes_number == video_frames_number) { print_warning("W60044", file_stats.st_size, "only keyframes detected and onLastSecond event present, file is probably not playable"); } /* check onLastSecond timestamp */ if (have_on_last_second && (last_timestamp - on_last_second_timestamp) >= 2000) { sprintf(message, "onLastSecond event located %d ms before the last tag", last_timestamp - on_last_second_timestamp); print_warning("W70050", file_stats.st_size, message); } /* check onMetaData presence */ if (!have_on_metadata) { print_warning("W70044", file_stats.st_size, "onMetaData event not found, file might not be playable"); } else { amf_node * n; int have_width, have_height; have_width = 0; have_height = 0; /* compute metadata */ opts_loc.verbose = 0; opts_loc.reset_timestamps = 0; opts_loc.preserve_metadata = 0; opts_loc.all_keyframes = 0; opts_loc.error_handling = FLVMETA_IGNORE_ERRORS; flv_reset(flv_in); if (get_flv_info(flv_in, &info, &opts_loc) != OK) { print_fatal("F10042", 0, "unable to compute metadata"); goto end; } /* more metadata checks */ for (n = amf_associative_array_first(on_metadata); n != NULL; n = amf_associative_array_next(n)) { byte * name; amf_data * data; byte type; name = amf_string_get_bytes(amf_associative_array_get_name(n)); data = amf_associative_array_get_data(n); type = amf_data_get_type(data); /* hasMetadata (bool): true */ if (!strcmp((char*)name, "hasMetadata")) { if (type == AMF_TYPE_BOOLEAN) { if (amf_boolean_get_value(data) == 0) { print_warning("W70045", on_metadata_offset, "hasMetadata should be set to true"); } } else { sprintf(message, "Invalid type for hasMetadata: expected %s, got %s", get_amf_type_string(AMF_TYPE_BOOLEAN), get_amf_type_string(type)); print_warning("W70046", on_metadata_offset, message); } } /* hasVideo (bool) */ if (!strcmp((char*)name, "hasVideo")) { if (type == AMF_TYPE_BOOLEAN) { if (amf_boolean_get_value(data) != info.have_video) { sprintf(message, "hasVideo should be set to %s", info.have_video ? "true" : "false"); print_warning("W70045", on_metadata_offset, message); } } else { sprintf(message, "Invalid type for hasVideo: expected %s, got %s", get_amf_type_string(AMF_TYPE_BOOLEAN), get_amf_type_string(type)); print_warning("W70046", on_metadata_offset, message); } } /* hasAudio (bool) */ if (!strcmp((char*)name, "hasAudio")) { if (type == AMF_TYPE_BOOLEAN) { if (amf_boolean_get_value(data) != info.have_audio) { sprintf(message, "hasAudio should be set to %s", info.have_audio ? "true" : "false"); print_warning("W70045", on_metadata_offset, message); } } else { sprintf(message, "Invalid type for hasAudio: expected %s, got %s", get_amf_type_string(AMF_TYPE_BOOLEAN), get_amf_type_string(type)); print_warning("W70046", on_metadata_offset, message); } } /* duration (number) */ if (!strcmp((char*)name, "duration")) { if (type == AMF_TYPE_NUMBER) { number64 duration, file_duration; if (info.have_audio) { duration = (info.last_timestamp - info.first_timestamp + info.audio_frame_duration) / 1000.0; } else { duration = (info.last_timestamp - info.first_timestamp + info.video_frame_duration) / 1000.0; } file_duration = amf_number_get_value(data); if (fabs(file_duration - duration) > 1.0) { sprintf(message, "duration should be %.12g, got %.12g", duration, file_duration); print_warning("W70045", on_metadata_offset, message); } } else { sprintf(message, "Invalid type for duration: expected %s, got %s", get_amf_type_string(AMF_TYPE_NUMBER), get_amf_type_string(type)); print_warning("W70046", on_metadata_offset, message); } } /* lasttimestamp: (number) */ /* lastkeyframetimestamp: (number) */ /* width: (number) */ /* height: (number) */ /* videodatarate: (number)*/ /* framerate: (number) */ /* audiodatarate: (number) */ /* audiosamplerate: (number) */ /* audiosamplesize: (number) */ /* stereo: (boolean) */ /* filesize: (number) */ /* videosize: (number) */ /* audiosize: (number) */ /* datasize: (number) */ /* audiocodecid: (number) */ /* videocodecid: (number) */ /* audiodelay: (number) */ /* canSeekToEnd: (boolean) */ /* hasKeyframes: (boolean) */ /* keyframes: (object) */ } /* missing width or height can cause size problem in various players */ if (!have_width) { print_error("E60047", on_metadata_offset, "width information not found in metadata, problems might occur in some players"); } if (!have_height) { print_error("E60047", on_metadata_offset, "height information not found in metadata, problems might occur in some players"); } } /* could we compute video resolution ? */ if (info.video_width == 0 && info.video_height == 0) { print_warning("W60044", file_stats.st_size, "unable to determine video resolution"); } end: report_end(opts, errors, warnings); amf_data_free(on_metadata); flv_close(flv_in); return (errors > 0) ? ERROR_INVALID_FLV_FILE : OK; }