Re: [問題] 兩程式間傳資料 stdout 與 stdin 的問題

看板C_and_CPP作者 ( )時間14年前 (2009/12/16 04:43), 編輯推噓1(105)
留言6則, 2人參與, 最新討論串2/2 (看更多)
經分析發現, AVS2WAV 使用的 AVIStreamRead() 會莫名奇妙產生兩次 MPEG 1.0 layer II ... 的訊息到 stdout 流中 使得後面用 stdin 來吃資料的程式會錯誤 但是後面的程式不能改 AVIStreamRead() 沒有原始碼 ( 參考 Vfw.h ) 有沒有辦法在程式呼叫 AVIStreamRead() 以前 讓一切不管是 stdout 還是 stderr 都不要被 stdout 然後呼叫完以後才還原 ==============以下是囉哩八唆的分析,問題已陳述在上======================

12/13 13:35,
唔...剛剛拿了個比較程式去比發現了一個嚴重的問題:
12/13 13:35

12/13 13:36,
avs2wav 在 scanning 時會輸出 MPEG 1.0 layer II ...的訊息
12/13 13:36

12/13 13:36,
但這些訊息並不是送去 stderr 的 而是送去 stdout 的...|||
12/13 13:36

12/13 13:36,
所以當輸出檔也輸出到 stdout 就會全部寫入檔案裡...orz
12/13 13:36

12/13 13:38,
然後這個訊息貌似不在 avs2wav.cpp 裡面..||
12/13 13:38

12/13 13:44,
OK, 確認問題是在那個地方了 orz 那個東西以外都是一樣的
12/13 13:44
如您所說,在很奇怪的地方,被加一些料到 stdout stream 中 用了簡單的 fprintf 已找出在 Avs2Ogg::ReadHeaders () 中的 while (bMoreStreams) { ... ret = AVIFileGetStream(m_AVIFile, &myAVIStream, 0, currentAVIStream); ... ret = AVIStreamInfo(myAVIStream, &myAVIStreamInfo, sizeof(myAVIStreamInfo)); ... } 上面分別呼叫的兩個函式 AVIFileGetStream, AVIStreamInfo 其中第一個在第一次呼叫時居然會自動印出 MPEG 1.0 layer II ...的訊息 而且被強制送到 stdout 另外仔細觀察發現那個 MPEG 1.0 layer II ...的訊息 假設完整長度是 20 (隨意舉例,沒去數) 標準 WAVE 檔頭是 RIFF 開頭 這個錯誤的 stdout 會在 RIFF 前面塞一大堆 MPEG 1.0 layer II ... 而且長度不是 20 的倍數,會不完整好像是 padding 字串一樣 而這部份很神奇的解法,居然是在 while 上面加一行 fprintf (stdout, ""); // 送出空字串到 stdout 就把這部份的詭異訊息屏蔽掉了 ....XD 但是這個 stdout 的 bug 還沒有完結 拿出 fc /b 作比較,address=0x4 的地方 也就是 緊接著 RIFF 四個字的字串後的 long 值 (Chunk Data Size) 就不一樣啦 PS: WAVE Header Format http://www.sonicspot.com/guide/wavefiles.html 平平都是一樣的 code 只差在 stdout 或是 檔案模式 怎麼連計算的結果都不一樣捏? 更怪的是後來用舊版程式再跑一遍 那個 "padding" 也不再出現了 (有 exit 再重回 console 也一樣 --> 大概要重開機 bug 才會再現吧) 再來的不同是 0x60000 之後 那個 MPEG 1.0 layer II 又來了 源於 AVIStreamRead() 還會產生兩次的 MPEG 1.0... 音軌錯誤就是斷在這裡 此外,手動去掉第二段的 MPEG 1.0 layer II 之後 結尾還多了 8 Bytes 的奇異資料 總而言之,真的只要把 MPEG 1.0 layer II 去掉 播放起來就沒有差別 可是 fprintf(stdout,""); 只能去掉第一段... 第二段就沒輒了 有辦法在呼叫 AVIStreamRead() 以前讓 他的 stdout 還是 stderr 不要真的背送出 stdout 然後呼叫完畢以後才還原? ============= 關於之前的讀 stdin 測試程式已修正完畢,感謝!

12/13 13:44,
然後你的測試程式的問題在於你用了 text mode 讀 stdin...
12/13 13:44

12/13 13:45,
所以碰到 0x1A 就被認為是 EOF 了
12/13 13:45
感謝指點, 忘記加了 setmode binary, 加了之後就可以讀了 #include "stdafx.h" #include <io.h> #include <fcntl.h> int _tmain(int argc, _TCHAR* argv[]) { FILE* pOut; int i=0; char byte; _setmode(_fileno( stdin ), _O_BINARY); fopen_s(&pOut,"stdouts.wav","wb"); while (fread(&byte,1,1,stdin)) i++; fwrite(&byte,1,1,pOut); printf("gets %d bytes from stdin\n",i); fclose(pOut); } -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 125.229.2.42

12/16 14:53, , 1F
問題絕大部分已經解決了喔, 用 CreatePipe() 把正確的導出
12/16 14:53, 1F

12/16 15:30, , 2F
最後多出的 8 byte 來自於原始程式想在 stdout 用 fseek
12/16 15:30, 2F

12/16 15:31, , 3F
但是覆水難收,這樣是不可行的,所以就附加在檔尾
12/16 15:31, 3F

12/16 15:32, , 4F
offset=4 也就是第5個 byte 開始的 4byte 錯誤
12/16 15:32, 4F

12/16 15:32, , 5F
源自於原始程式碼對檔案大小的錯誤估計. 修正後就正常了
12/16 15:32, 5F

12/16 16:05, , 6F
推一下原po查出問題有回來總結:)
12/16 16:05, 6F
文章代碼(AID): #1B9_KELF (C_and_CPP)
文章代碼(AID): #1B9_KELF (C_and_CPP)