Mercurial > libavformat.hg
comparison nut.c @ 419:51c25922a543 libavformat
search for undamaged headers
author | michael |
---|---|
date | Mon, 05 Apr 2004 22:00:59 +0000 |
parents | 41da3366d341 |
children | a35263593560 |
comparison
equal
deleted
inserted
replaced
418:41da3366d341 | 419:51c25922a543 |
---|---|
88 int64_t last_packet_start; | 88 int64_t last_packet_start; |
89 int written_packet_size; | 89 int written_packet_size; |
90 int64_t packet_size_pos; | 90 int64_t packet_size_pos; |
91 int64_t last_frame_start[3]; | 91 int64_t last_frame_start[3]; |
92 FrameCode frame_code[256]; | 92 FrameCode frame_code[256]; |
93 int stream_count; | |
93 StreamContext *stream; | 94 StreamContext *stream; |
94 } NUTContext; | 95 } NUTContext; |
95 | 96 |
96 static char *info_table[][2]={ | 97 static char *info_table[][2]={ |
97 {NULL , NULL }, // end | 98 {NULL , NULL }, // end |
326 return i; | 327 return i; |
327 | 328 |
328 return 7; //not reached | 329 return 7; //not reached |
329 } | 330 } |
330 | 331 |
332 static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ | |
333 uint64_t state=0; | |
334 | |
335 if(pos >= 0) | |
336 url_fseek(bc, pos, SEEK_SET); //note, this may fail if the stream isnt seekable, but that shouldnt matter, as in this case we simply start where we are currently | |
337 | |
338 while(bytes_left(bc)){ | |
339 state= (state<<8) | get_byte(bc); | |
340 if((state>>56) != 'N') | |
341 continue; | |
342 switch(state){ | |
343 case MAIN_STARTCODE: | |
344 case STREAM_STARTCODE: | |
345 case KEYFRAME_STARTCODE: | |
346 case INFO_STARTCODE: | |
347 case INDEX_STARTCODE: | |
348 return state; | |
349 } | |
350 } | |
351 return 0; | |
352 } | |
353 | |
354 static int find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){ | |
355 for(;;){ | |
356 uint64_t startcode= find_any_startcode(bc, pos); | |
357 if(startcode == code) | |
358 return 0; | |
359 else if(startcode == 0) | |
360 return -1; | |
361 pos=-1; | |
362 } | |
363 } | |
364 | |
331 #ifdef CONFIG_ENCODERS | 365 #ifdef CONFIG_ENCODERS |
332 static int put_v(ByteIOContext *bc, uint64_t val) | 366 static int put_v(ByteIOContext *bc, uint64_t val) |
333 { | 367 { |
334 int i; | 368 int i; |
335 // if (bytes_left(s)*8 < 9) | 369 // if (bytes_left(s)*8 < 9) |
761 return AVPROBE_SCORE_MAX; | 795 return AVPROBE_SCORE_MAX; |
762 } | 796 } |
763 return 0; | 797 return 0; |
764 } | 798 } |
765 | 799 |
766 static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) | 800 static int decode_main_header(NUTContext *nut){ |
767 { | 801 AVFormatContext *s= nut->avf; |
768 NUTContext *nut = s->priv_data; | |
769 ByteIOContext *bc = &s->pb; | 802 ByteIOContext *bc = &s->pb; |
770 uint64_t tmp; | 803 uint64_t tmp; |
771 int cur_stream, nb_streams, i, j; | 804 int i, j; |
772 | 805 |
773 nut->avf= s; | |
774 | |
775 av_set_pts_info(s, 60, 1, AV_TIME_BASE); | |
776 | |
777 /* main header */ | |
778 tmp = get_be64(bc); | |
779 if (tmp != MAIN_STARTCODE) | |
780 av_log(s, AV_LOG_ERROR, "damaged? startcode!=1 (%Ld)\n", tmp); | |
781 get_packetheader(nut, bc, 8, 1); | 806 get_packetheader(nut, bc, 8, 1); |
782 | 807 |
783 tmp = get_v(bc); | 808 tmp = get_v(bc); |
784 if (tmp != 1) | 809 if (tmp != 1){ |
785 av_log(s, AV_LOG_ERROR, "bad version (%Ld)\n", tmp); | 810 av_log(s, AV_LOG_ERROR, "bad version (%Ld)\n", tmp); |
786 | 811 return -1; |
787 nb_streams = get_v(bc); | 812 } |
813 | |
814 nut->stream_count = get_v(bc); | |
788 get_v(bc); //checksum threshold | 815 get_v(bc); //checksum threshold |
789 | 816 |
790 for(i=0; i<256;){ | 817 for(i=0; i<256;){ |
791 int tmp_flags = get_v(bc); | 818 int tmp_flags = get_v(bc); |
792 int tmp_stream= get_v(bc); | 819 int tmp_stream= get_v(bc); |
809 return -1; | 836 return -1; |
810 } | 837 } |
811 } | 838 } |
812 | 839 |
813 for(j=0; j<count; j++,i++){ | 840 for(j=0; j<count; j++,i++){ |
814 if(tmp_stream > nb_streams + 1){ | 841 if(tmp_stream > nut->stream_count + 1){ |
815 av_log(s, AV_LOG_ERROR, "illegal stream number\n"); | 842 av_log(s, AV_LOG_ERROR, "illegal stream number\n"); |
816 return -1; | 843 return -1; |
817 } | 844 } |
818 | 845 |
819 nut->frame_code[i].flags = tmp_flags ; | 846 nut->frame_code[i].flags = tmp_flags ; |
828 } | 855 } |
829 if(nut->frame_code['N'].flags != 1){ | 856 if(nut->frame_code['N'].flags != 1){ |
830 av_log(s, AV_LOG_ERROR, "illegal frame_code table\n"); | 857 av_log(s, AV_LOG_ERROR, "illegal frame_code table\n"); |
831 return -1; | 858 return -1; |
832 } | 859 } |
833 | 860 |
834 if(check_checksum(bc)){ | 861 if(check_checksum(bc)){ |
835 av_log(s, AV_LOG_ERROR, "Main header checksum missmatch\n"); | 862 av_log(s, AV_LOG_ERROR, "Main header checksum missmatch\n"); |
836 return -1; | 863 return -1; |
837 } | 864 } |
865 | |
866 return 0; | |
867 } | |
868 | |
869 static int decode_stream_header(NUTContext *nut){ | |
870 AVFormatContext *s= nut->avf; | |
871 ByteIOContext *bc = &s->pb; | |
872 int class, nom, denom, stream_id, i; | |
873 uint64_t tmp; | |
874 AVStream *st; | |
875 | |
876 get_packetheader(nut, bc, 8, 1); | |
877 stream_id= get_v(bc); | |
878 if(stream_id >= nut->stream_count || s->streams[stream_id]) | |
879 return -1; | |
880 | |
881 st = av_new_stream(s, stream_id); | |
882 if (!st) | |
883 return AVERROR_NOMEM; | |
884 class = get_v(bc); | |
885 tmp = get_v(bc); | |
886 switch(class) | |
887 { | |
888 case 0: | |
889 st->codec.codec_type = CODEC_TYPE_VIDEO; | |
890 st->codec.codec_id = codec_get_bmp_id(tmp); | |
891 if (st->codec.codec_id == CODEC_ID_NONE) | |
892 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
893 break; | |
894 case 32: | |
895 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
896 st->codec.codec_id = codec_get_wav_id(tmp); | |
897 if (st->codec.codec_id == CODEC_ID_NONE) | |
898 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
899 break; | |
900 default: | |
901 av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class); | |
902 return -1; | |
903 } | |
904 s->bit_rate += get_v(bc); | |
905 get_v(bc); /* language code */ | |
906 nom = get_v(bc); | |
907 denom = get_v(bc); | |
908 nut->stream[stream_id].msb_timestamp_shift = get_v(bc); | |
909 for(i=0; i<3; i++) | |
910 nut->stream[stream_id].initial_pts_predictor[i]= get_v(bc); | |
911 for(i=0; i<2; i++) | |
912 nut->stream[stream_id].initial_size_predictor[i]= get_v(bc); | |
913 get_byte(bc); /* flags */ | |
914 | |
915 /* codec specific data headers */ | |
916 while(get_v(bc) != 0){ | |
917 st->codec.extradata_size= get_v(bc); | |
918 st->codec.extradata= av_mallocz(st->codec.extradata_size); | |
919 get_buffer(bc, st->codec.extradata, st->codec.extradata_size); | |
920 // url_fskip(bc, get_v(bc)); | |
921 } | |
922 | |
923 if (class == 0) /* VIDEO */ | |
924 { | |
925 st->codec.width = get_v(bc); | |
926 st->codec.height = get_v(bc); | |
927 st->codec.sample_aspect_ratio.num= get_v(bc); | |
928 st->codec.sample_aspect_ratio.den= get_v(bc); | |
929 get_v(bc); /* csp type */ | |
930 | |
931 st->codec.frame_rate = nom; | |
932 st->codec.frame_rate_base = denom; | |
933 } | |
934 if (class == 32) /* AUDIO */ | |
935 { | |
936 st->codec.sample_rate = (get_v(bc) * nom) / denom; | |
937 st->codec.channels = get_v(bc); | |
938 } | |
939 if(check_checksum(bc)){ | |
940 av_log(s, AV_LOG_ERROR, "Stream header %d checksum missmatch\n", stream_id); | |
941 return -1; | |
942 } | |
943 nut->stream[stream_id].rate_num= nom; | |
944 nut->stream[stream_id].rate_den= denom; | |
945 return 0; | |
946 } | |
947 | |
948 static int decode_info_header(NUTContext *nut){ | |
949 AVFormatContext *s= nut->avf; | |
950 ByteIOContext *bc = &s->pb; | |
951 | |
952 get_packetheader(nut, bc, 8, 1); | |
953 | |
954 for(;;){ | |
955 int id= get_v(bc); | |
956 char *name, *type, custom_name[256], custom_type[256]; | |
957 | |
958 if(!id) | |
959 break; | |
960 else if(id >= sizeof(info_table)/sizeof(info_table[0])){ | |
961 av_log(s, AV_LOG_ERROR, "info id is too large %d %d\n", id, sizeof(info_table)/sizeof(info_table[0])); | |
962 return -1; | |
963 } | |
964 | |
965 type= info_table[id][1]; | |
966 name= info_table[id][0]; | |
967 //av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name); | |
968 | |
969 if(!type){ | |
970 get_str(bc, custom_type, sizeof(custom_type)); | |
971 type= custom_type; | |
972 } | |
973 if(!name){ | |
974 get_str(bc, custom_name, sizeof(custom_name)); | |
975 name= custom_name; | |
976 } | |
977 | |
978 if(!strcmp(type, "v")){ | |
979 int value= get_v(bc); | |
980 }else{ | |
981 if(!strcmp(name, "Author")) | |
982 get_str(bc, s->author, sizeof(s->author)); | |
983 else if(!strcmp(name, "Title")) | |
984 get_str(bc, s->title, sizeof(s->title)); | |
985 else if(!strcmp(name, "Copyright")) | |
986 get_str(bc, s->copyright, sizeof(s->copyright)); | |
987 else if(!strcmp(name, "Description")) | |
988 get_str(bc, s->comment, sizeof(s->comment)); | |
989 else | |
990 get_str(bc, NULL, 0); | |
991 } | |
992 } | |
993 if(check_checksum(bc)){ | |
994 av_log(s, AV_LOG_ERROR, "Info header checksum missmatch\n"); | |
995 return -1; | |
996 } | |
997 return 0; | |
998 } | |
999 | |
1000 static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) | |
1001 { | |
1002 NUTContext *nut = s->priv_data; | |
1003 ByteIOContext *bc = &s->pb; | |
1004 int64_t pos; | |
1005 int inited_stream_count; | |
1006 | |
1007 nut->avf= s; | |
1008 | |
1009 av_set_pts_info(s, 60, 1, AV_TIME_BASE); | |
1010 | |
1011 /* main header */ | |
1012 pos=0; | |
1013 for(;;){ | |
1014 if (find_startcode(bc, MAIN_STARTCODE, pos)<0){ | |
1015 av_log(s, AV_LOG_ERROR, "no main startcode found\n"); | |
1016 return -1; | |
1017 } | |
1018 pos= url_ftell(bc); | |
1019 if(decode_main_header(nut) >= 0) | |
1020 break; | |
1021 } | |
1022 | |
838 | 1023 |
839 s->bit_rate = 0; | 1024 s->bit_rate = 0; |
840 | 1025 |
841 nut->stream = av_malloc(sizeof(StreamContext)*nb_streams); | 1026 nut->stream = av_malloc(sizeof(StreamContext)*nut->stream_count); |
842 | 1027 |
843 /* stream header */ | 1028 /* stream headers */ |
844 for (cur_stream = 0; cur_stream < nb_streams; cur_stream++) | 1029 pos=0; |
845 { | 1030 for(inited_stream_count=0; inited_stream_count < nut->stream_count;){ |
846 int class, nom, denom; | 1031 if (find_startcode(bc, STREAM_STARTCODE, pos)<0){ |
847 AVStream *st; | 1032 av_log(s, AV_LOG_ERROR, "not all stream headers found\n"); |
848 | |
849 tmp = get_be64(bc); | |
850 if (tmp != STREAM_STARTCODE) | |
851 av_log(s, AV_LOG_ERROR, "damaged? startcode!=1 (%Ld)\n", tmp); | |
852 get_packetheader(nut, bc, 8, 1); | |
853 st = av_new_stream(s, get_v(bc)); | |
854 if (!st) | |
855 return AVERROR_NOMEM; | |
856 class = get_v(bc); | |
857 tmp = get_v(bc); | |
858 switch(class) | |
859 { | |
860 case 0: | |
861 st->codec.codec_type = CODEC_TYPE_VIDEO; | |
862 st->codec.codec_id = codec_get_bmp_id(tmp); | |
863 if (st->codec.codec_id == CODEC_ID_NONE) | |
864 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
865 break; | |
866 case 32: | |
867 st->codec.codec_type = CODEC_TYPE_AUDIO; | |
868 st->codec.codec_id = codec_get_wav_id(tmp); | |
869 if (st->codec.codec_id == CODEC_ID_NONE) | |
870 av_log(s, AV_LOG_ERROR, "Unknown codec?!\n"); | |
871 break; | |
872 default: | |
873 av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class); | |
874 return -1; | |
875 } | |
876 s->bit_rate += get_v(bc); | |
877 get_v(bc); /* language code */ | |
878 nom = get_v(bc); | |
879 denom = get_v(bc); | |
880 nut->stream[cur_stream].msb_timestamp_shift = get_v(bc); | |
881 for(i=0; i<3; i++) | |
882 nut->stream[cur_stream].initial_pts_predictor[i]= get_v(bc); | |
883 for(i=0; i<2; i++) | |
884 nut->stream[cur_stream].initial_size_predictor[i]= get_v(bc); | |
885 get_byte(bc); /* flags */ | |
886 | |
887 /* codec specific data headers */ | |
888 while(get_v(bc) != 0){ | |
889 st->codec.extradata_size= get_v(bc); | |
890 st->codec.extradata= av_mallocz(st->codec.extradata_size); | |
891 get_buffer(bc, st->codec.extradata, st->codec.extradata_size); | |
892 // url_fskip(bc, get_v(bc)); | |
893 } | |
894 | |
895 if (class == 0) /* VIDEO */ | |
896 { | |
897 st->codec.width = get_v(bc); | |
898 st->codec.height = get_v(bc); | |
899 st->codec.sample_aspect_ratio.num= get_v(bc); | |
900 st->codec.sample_aspect_ratio.den= get_v(bc); | |
901 get_v(bc); /* csp type */ | |
902 | |
903 st->codec.frame_rate = nom; | |
904 st->codec.frame_rate_base = denom; | |
905 } | |
906 if (class == 32) /* AUDIO */ | |
907 { | |
908 st->codec.sample_rate = (get_v(bc) * nom) / denom; | |
909 st->codec.channels = get_v(bc); | |
910 } | |
911 if(check_checksum(bc)){ | |
912 av_log(s, AV_LOG_ERROR, "Stream header %d checksum missmatch\n", cur_stream); | |
913 return -1; | 1033 return -1; |
914 } | 1034 } |
915 nut->stream[cur_stream].rate_num= nom; | 1035 pos= url_ftell(bc); |
916 nut->stream[cur_stream].rate_den= denom; | 1036 if(decode_stream_header(nut) >= 0) |
917 } | 1037 inited_stream_count++; |
918 | 1038 } |
919 tmp = get_be64(bc); | 1039 |
920 if (tmp == INFO_STARTCODE){ | 1040 /* info headers */ |
921 get_packetheader(nut, bc, 8, 1); | 1041 pos=0; |
922 | 1042 for(;;){ |
923 for(;;){ | 1043 uint64_t startcode= find_any_startcode(bc, pos); |
924 int id= get_v(bc); | 1044 pos= url_ftell(bc); |
925 char *name, *type, custom_name[256], custom_type[256]; | 1045 |
926 | 1046 if(startcode==0){ |
927 if(!id) | 1047 av_log(s, AV_LOG_ERROR, "EOF before video frames\n"); |
928 break; | 1048 return -1; |
929 else if(id >= sizeof(info_table)/sizeof(info_table[0])){ | 1049 }else if(startcode == KEYFRAME_STARTCODE){ |
930 av_log(s, AV_LOG_ERROR, "info id is too large %d %d\n", id, sizeof(info_table)/sizeof(info_table[0])); | 1050 url_fseek(bc, -8, SEEK_CUR); //FIXME |
931 return -1; | 1051 break; |
932 } | 1052 }else if(startcode != INFO_STARTCODE){ |
933 | 1053 continue; |
934 type= info_table[id][1]; | 1054 } |
935 name= info_table[id][0]; | 1055 |
936 //av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name); | 1056 decode_info_header(nut); |
937 | 1057 } |
938 if(!type){ | 1058 |
939 get_str(bc, custom_type, sizeof(custom_type)); | |
940 type= custom_type; | |
941 } | |
942 if(!name){ | |
943 get_str(bc, custom_name, sizeof(custom_name)); | |
944 name= custom_name; | |
945 } | |
946 | |
947 if(!strcmp(type, "v")){ | |
948 int value= get_v(bc); | |
949 }else{ | |
950 if(!strcmp(name, "Author")) | |
951 get_str(bc, s->author, sizeof(s->author)); | |
952 else if(!strcmp(name, "Title")) | |
953 get_str(bc, s->title, sizeof(s->title)); | |
954 else if(!strcmp(name, "Copyright")) | |
955 get_str(bc, s->copyright, sizeof(s->copyright)); | |
956 else if(!strcmp(name, "Description")) | |
957 get_str(bc, s->comment, sizeof(s->comment)); | |
958 else | |
959 get_str(bc, NULL, 0); | |
960 } | |
961 } | |
962 if(check_checksum(bc)){ | |
963 av_log(s, AV_LOG_ERROR, "Info header checksum missmatch\n"); | |
964 } | |
965 }else | |
966 url_fseek(bc, -8, SEEK_CUR); | |
967 | |
968 return 0; | 1059 return 0; |
969 } | 1060 } |
970 | 1061 |
971 static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) | 1062 static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) |
972 { | 1063 { |